aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/qml/qqmlecmascript
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/qml/qqmlecmascript')
-rw-r--r--tests/auto/qml/qqmlecmascript/data/AliasBindingsAssignCorrectlyType.qml9
-rw-r--r--tests/auto/qml/qqmlecmascript/data/AliasBindingsOverrideTargetType.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/data/AliasBindingsOverrideTargetType3.qml9
-rw-r--r--tests/auto/qml/qqmlecmascript/data/AliasToCompositeElementType1.qml6
-rw-r--r--tests/auto/qml/qqmlecmascript/data/AliasToCompositeElementType2.qml5
-rw-r--r--tests/auto/qml/qqmlecmascript/data/ConstantsOverrideBindings.qml12
-rw-r--r--tests/auto/qml/qqmlecmascript/data/CustomObject.qml5
-rw-r--r--tests/auto/qml/qqmlecmascript/data/ElementAssignType.qml5
-rw-r--r--tests/auto/qml/qqmlecmascript/data/MethodsObject.qml6
-rw-r--r--tests/auto/qml/qqmlecmascript/data/NestedTypeTransientErrors.qml11
-rw-r--r--tests/auto/qml/qqmlecmascript/data/PropertyVarBaseItem.qml5
-rw-r--r--tests/auto/qml/qqmlecmascript/data/PropertyVarCircularComponent.qml23
-rw-r--r--tests/auto/qml/qqmlecmascript/data/PropertyVarCircularComponent2.qml26
-rw-r--r--tests/auto/qml/qqmlecmascript/data/PropertyVarCircularComponent3.qml16
-rw-r--r--tests/auto/qml/qqmlecmascript/data/PropertyVarCircularComponent4.qml28
-rw-r--r--tests/auto/qml/qqmlecmascript/data/PropertyVarCircularComponent5.qml7
-rw-r--r--tests/auto/qml/qqmlecmascript/data/PropertyVarInheritanceComponent.qml22
-rw-r--r--tests/auto/qml/qqmlecmascript/data/PropertyVarOwnershipComponent.qml37
-rw-r--r--tests/auto/qml/qqmlecmascript/data/ScarceResourceSignalComponentVar.qml9
-rw-r--r--tests/auto/qml/qqmlecmascript/data/ScarceResourceSignalComponentVariant.qml9
-rw-r--r--tests/auto/qml/qqmlecmascript/data/ScarceResourceVarComponent.qml13
-rw-r--r--tests/auto/qml/qqmlecmascript/data/Scope6Nested.qml7
-rw-r--r--tests/auto/qml/qqmlecmascript/data/ScopeObject.qml12
-rw-r--r--tests/auto/qml/qqmlecmascript/data/SequenceConversionComponent.qml7
-rw-r--r--tests/auto/qml/qqmlecmascript/data/SpuriousWarning.qml5
-rw-r--r--tests/auto/qml/qqmlecmascript/data/TypeForDynamicCreation.qml2
-rw-r--r--tests/auto/qml/qqmlecmascript/data/aliasBindingsAssignCorrectly.qml59
-rw-r--r--tests/auto/qml/qqmlecmascript/data/aliasBindingsOverrideTarget.2.qml29
-rw-r--r--tests/auto/qml/qqmlecmascript/data/aliasBindingsOverrideTarget.3.qml24
-rw-r--r--tests/auto/qml/qqmlecmascript/data/aliasBindingsOverrideTarget.qml28
-rw-r--r--tests/auto/qml/qqmlecmascript/data/aliasPropertyAndBinding.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/data/aliasToCompositeElement.qml6
-rw-r--r--tests/auto/qml/qqmlecmascript/data/aliasWritesOverrideBindings.2.qml29
-rw-r--r--tests/auto/qml/qqmlecmascript/data/aliasWritesOverrideBindings.3.qml23
-rw-r--r--tests/auto/qml/qqmlecmascript/data/aliasWritesOverrideBindings.qml23
-rw-r--r--tests/auto/qml/qqmlecmascript/data/aliasreset/AliasPropertyComponent.qml17
-rw-r--r--tests/auto/qml/qqmlecmascript/data/aliasreset/aliasPropertyReset.1.qml23
-rw-r--r--tests/auto/qml/qqmlecmascript/data/aliasreset/aliasPropertyReset.2.qml23
-rw-r--r--tests/auto/qml/qqmlecmascript/data/aliasreset/aliasPropertyReset.3.qml31
-rw-r--r--tests/auto/qml/qqmlecmascript/data/aliasreset/aliasPropertyReset.4.qml26
-rw-r--r--tests/auto/qml/qqmlecmascript/data/aliasreset/aliasPropertyReset.5.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/data/aliasreset/aliasPropertyReset.error.1.qml18
-rw-r--r--tests/auto/qml/qqmlecmascript/data/assignBasicTypes.2.qml26
-rw-r--r--tests/auto/qml/qqmlecmascript/data/assignBasicTypes.qml29
-rw-r--r--tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.1.qml11
-rw-r--r--tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.2.qml11
-rw-r--r--tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.3.qml9
-rw-r--r--tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.4.qml13
-rw-r--r--tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.5.qml13
-rw-r--r--tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.6.qml11
-rw-r--r--tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.7.qml42
-rw-r--r--tests/auto/qml/qqmlecmascript/data/attachedProperty.2.qml22
-rw-r--r--tests/auto/qml/qqmlecmascript/data/attachedProperty.qml11
-rw-r--r--tests/auto/qml/qqmlecmascript/data/attachedPropertyScope.qml9
-rw-r--r--tests/auto/qml/qqmlecmascript/data/automaticSemicolon.qml11
-rw-r--r--tests/auto/qml/qqmlecmascript/data/bindingLoop.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/data/blank.js0
-rw-r--r--tests/auto/qml/qqmlecmascript/data/boolPropertiesEvaluateAsBool.1.qml5
-rw-r--r--tests/auto/qml/qqmlecmascript/data/boolPropertiesEvaluateAsBool.2.qml5
-rw-r--r--tests/auto/qml/qqmlecmascript/data/booleanConversion.qml28
-rw-r--r--tests/auto/qml/qqmlecmascript/data/bug.1.qml10
-rw-r--r--tests/auto/qml/qqmlecmascript/data/canAssignNullToQObject.1.qml9
-rw-r--r--tests/auto/qml/qqmlecmascript/data/canAssignNullToQObject.2.qml11
-rw-r--r--tests/auto/qml/qqmlecmascript/data/changeslots/propertyChangeSlotErrors.1.qml12
-rw-r--r--tests/auto/qml/qqmlecmascript/data/changeslots/propertyChangeSlotErrors.2.qml12
-rw-r--r--tests/auto/qml/qqmlecmascript/data/changeslots/propertyChangeSlotErrors.3.qml12
-rw-r--r--tests/auto/qml/qqmlecmascript/data/changeslots/propertyChangeSlotErrors.4.qml12
-rw-r--r--tests/auto/qml/qqmlecmascript/data/changeslots/propertyChangeSlots.qml27
-rw-r--r--tests/auto/qml/qqmlecmascript/data/compiled.qml48
-rw-r--r--tests/auto/qml/qqmlecmascript/data/compositePropertyType.qml8
-rw-r--r--tests/auto/qml/qqmlecmascript/data/constantsOverrideBindings.1.qml8
-rw-r--r--tests/auto/qml/qqmlecmascript/data/constantsOverrideBindings.2.qml11
-rw-r--r--tests/auto/qml/qqmlecmascript/data/constantsOverrideBindings.3.qml7
-rw-r--r--tests/auto/qml/qqmlecmascript/data/constantsOverrideBindings.4.qml11
-rw-r--r--tests/auto/qml/qqmlecmascript/data/deferredProperties.qml10
-rw-r--r--tests/auto/qml/qqmlecmascript/data/deferredPropertiesErrors.qml10
-rw-r--r--tests/auto/qml/qqmlecmascript/data/deleteLater.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/data/deleteWhileBindingRunning.qml5
-rw-r--r--tests/auto/qml/qqmlecmascript/data/deletedEngine.qml11
-rw-r--r--tests/auto/qml/qqmlecmascript/data/deletedObject.qml25
-rw-r--r--tests/auto/qml/qqmlecmascript/data/doubleEvaluate.qml6
-rw-r--r--tests/auto/qml/qqmlecmascript/data/dynamicCreation.helper.qml6
-rw-r--r--tests/auto/qml/qqmlecmascript/data/dynamicCreation.qml27
-rw-r--r--tests/auto/qml/qqmlecmascript/data/dynamicCreationOwnership.qml20
-rw-r--r--tests/auto/qml/qqmlecmascript/data/dynamicDeletion.2.qml21
-rw-r--r--tests/auto/qml/qqmlecmascript/data/dynamicDeletion.qml20
-rw-r--r--tests/auto/qml/qqmlecmascript/data/dynamicString.qml16
-rw-r--r--tests/auto/qml/qqmlecmascript/data/elementAssign.qml10
-rw-r--r--tests/auto/qml/qqmlecmascript/data/enums.1.qml20
-rw-r--r--tests/auto/qml/qqmlecmascript/data/enums.2.qml8
-rw-r--r--tests/auto/qml/qqmlecmascript/data/eval.qml27
-rw-r--r--tests/auto/qml/qqmlecmascript/data/exception.js1
-rw-r--r--tests/auto/qml/qqmlecmascript/data/exceptionClearsOnReeval.qml6
-rw-r--r--tests/auto/qml/qqmlecmascript/data/exceptionProducesWarning.qml8
-rw-r--r--tests/auto/qml/qqmlecmascript/data/exceptionProducesWarning2.qml7
-rw-r--r--tests/auto/qml/qqmlecmascript/data/extendedObjectPropertyLookup.qml8
-rw-r--r--tests/auto/qml/qqmlecmascript/data/extendedObjectPropertyLookup2.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/data/extensionObjects.qml19
-rw-r--r--tests/auto/qml/qqmlecmascript/data/extensionObjectsPropertyOverride.qml7
-rw-r--r--tests/auto/qml/qqmlecmascript/data/forInLoop.qml13
-rw-r--r--tests/auto/qml/qqmlecmascript/data/function.qml23
-rw-r--r--tests/auto/qml/qqmlecmascript/data/functionAssignment.1.qml5
-rw-r--r--tests/auto/qml/qqmlecmascript/data/functionAssignment.2.qml73
-rw-r--r--tests/auto/qml/qqmlecmascript/data/functionAssignment.js17
-rw-r--r--tests/auto/qml/qqmlecmascript/data/functionErrors.qml10
-rw-r--r--tests/auto/qml/qqmlecmascript/data/handleReferenceManagement.handle.1.qml21
-rw-r--r--tests/auto/qml/qqmlecmascript/data/handleReferenceManagement.handle.2.qml22
-rw-r--r--tests/auto/qml/qqmlecmascript/data/handleReferenceManagement.object.1.qml27
-rw-r--r--tests/auto/qml/qqmlecmascript/data/handleReferenceManagement.object.2.qml28
-rw-r--r--tests/auto/qml/qqmlecmascript/data/idShortcutInvalidates.1.qml13
-rw-r--r--tests/auto/qml/qqmlecmascript/data/idShortcutInvalidates.qml12
-rw-r--r--tests/auto/qml/qqmlecmascript/data/importScope.1.js1
-rw-r--r--tests/auto/qml/qqmlecmascript/data/importScope.2.js3
-rw-r--r--tests/auto/qml/qqmlecmascript/data/importScope.qml7
-rw-r--r--tests/auto/qml/qqmlecmascript/data/in.qml7
-rw-r--r--tests/auto/qml/qqmlecmascript/data/include.js8
-rw-r--r--tests/auto/qml/qqmlecmascript/data/include.qml23
-rw-r--r--tests/auto/qml/qqmlecmascript/data/include_callback.js11
-rw-r--r--tests/auto/qml/qqmlecmascript/data/include_callback.qml15
-rw-r--r--tests/auto/qml/qqmlecmascript/data/include_pragma.qml11
-rw-r--r--tests/auto/qml/qqmlecmascript/data/include_pragma_inner.js5
-rw-r--r--tests/auto/qml/qqmlecmascript/data/include_pragma_outer.js6
-rw-r--r--tests/auto/qml/qqmlecmascript/data/include_remote.js26
-rw-r--r--tests/auto/qml/qqmlecmascript/data/include_remote.qml21
-rw-r--r--tests/auto/qml/qqmlecmascript/data/include_remote_missing.js13
-rw-r--r--tests/auto/qml/qqmlecmascript/data/include_remote_missing.qml12
-rw-r--r--tests/auto/qml/qqmlecmascript/data/include_shared.js12
-rw-r--r--tests/auto/qml/qqmlecmascript/data/include_shared.qml22
-rw-r--r--tests/auto/qml/qqmlecmascript/data/invokableObjectArg.qml9
-rw-r--r--tests/auto/qml/qqmlecmascript/data/invokableObjectRet.qml11
-rw-r--r--tests/auto/qml/qqmlecmascript/data/js/include2.js4
-rw-r--r--tests/auto/qml/qqmlecmascript/data/js/include3.js3
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsObject.qml12
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/SpecialRectangleOne.qml9
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/SpecialRectangleTwo.qml9
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/importFive.js3
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/importFour.js9
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/importModuleApi.js5
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/importOne.js13
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/importPragmaLibrary.js9
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/importPragmaLibraryWithImports.js9
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/importPragmaLibraryWithPragmaLibraryImports.js11
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/importThree.js9
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/importTwo.js10
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/importWithNoImports.js11
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/testImport.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/testImportModuleApi.qml10
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/testImportPragmaLibrary.qml20
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/testImportPragmaLibraryWithImports.qml7
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml7
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/testImportScoping.qml11
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/testModuleImport.js8
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimport/testScriptImport.js11
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimportfail/failFive.qml11
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimportfail/failFour.qml7
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimportfail/failOne.qml7
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimportfail/failThree.qml8
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimportfail/failTwo.qml7
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimportfail/importOne.js7
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimportfail/importPragmaLibrary.js11
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimportfail/importWithImports.js13
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimportfail/testImportPragmaLibrary.qml8
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimportfail/testModuleImport.js8
-rw-r--r--tests/auto/qml/qqmlecmascript/data/jsimportfail/testScriptImport.js11
-rw-r--r--tests/auto/qml/qqmlecmascript/data/libraryScriptAssert.js6
-rw-r--r--tests/auto/qml/qqmlecmascript/data/libraryScriptAssert.qml7
-rw-r--r--tests/auto/qml/qqmlecmascript/data/listAssignment.qml20
-rw-r--r--tests/auto/qml/qqmlecmascript/data/listProperties.qml24
-rw-r--r--tests/auto/qml/qqmlecmascript/data/listToVariant.qml5
-rw-r--r--tests/auto/qml/qqmlecmascript/data/metaobjectRevision.qml7
-rw-r--r--tests/auto/qml/qqmlecmascript/data/metaobjectRevision2.qml9
-rw-r--r--tests/auto/qml/qqmlecmascript/data/metaobjectRevision3.qml8
-rw-r--r--tests/auto/qml/qqmlecmascript/data/metaobjectRevision4.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/data/metaobjectRevisionErrors.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/data/metaobjectRevisionErrors2.qml24
-rw-r--r--tests/auto/qml/qqmlecmascript/data/metaobjectRevisionErrors3.qml36
-rw-r--r--tests/auto/qml/qqmlecmascript/data/methods.1.qml6
-rw-r--r--tests/auto/qml/qqmlecmascript/data/methods.2.qml6
-rw-r--r--tests/auto/qml/qqmlecmascript/data/methods.3.qml7
-rw-r--r--tests/auto/qml/qqmlecmascript/data/methods.4.qml11
-rw-r--r--tests/auto/qml/qqmlecmascript/data/methods.5.qml9
-rw-r--r--tests/auto/qml/qqmlecmascript/data/moduleapi/moduleApiMajorVersionFail.qml10
-rw-r--r--tests/auto/qml/qqmlecmascript/data/moduleapi/moduleApiMinorVersionFail.qml10
-rw-r--r--tests/auto/qml/qqmlecmascript/data/moduleapi/qobjectModuleApi.qml21
-rw-r--r--tests/auto/qml/qqmlecmascript/data/moduleapi/qobjectModuleApiCaching.qml10
-rw-r--r--tests/auto/qml/qqmlecmascript/data/moduleapi/qobjectModuleApiEnums.qml8
-rw-r--r--tests/auto/qml/qqmlecmascript/data/moduleapi/qobjectModuleApiWriting.qml26
-rw-r--r--tests/auto/qml/qqmlecmascript/data/moduleapi/scriptModuleApi.qml6
-rw-r--r--tests/auto/qml/qqmlecmascript/data/moduleapi/scriptModuleApiCaching.qml6
-rw-r--r--tests/auto/qml/qqmlecmascript/data/moduleapi/scriptModuleApiWriting.qml32
-rw-r--r--tests/auto/qml/qqmlecmascript/data/multiEngineObject.qml5
-rw-r--r--tests/auto/qml/qqmlecmascript/data/noSpuriousWarningsAtShutdown.2.qml10
-rw-r--r--tests/auto/qml/qqmlecmascript/data/noSpuriousWarningsAtShutdown.qml9
-rw-r--r--tests/auto/qml/qqmlecmascript/data/nonExistentAttachedObject.qml5
-rw-r--r--tests/auto/qml/qqmlecmascript/data/nonNotifyable.qml6
-rw-r--r--tests/auto/qml/qqmlecmascript/data/nonscriptable.qml19
-rw-r--r--tests/auto/qml/qqmlecmascript/data/nullObjectBinding.qml8
-rw-r--r--tests/auto/qml/qqmlecmascript/data/numberAssignment.qml18
-rw-r--r--tests/auto/qml/qqmlecmascript/data/objectConversion.qml16
-rw-r--r--tests/auto/qml/qqmlecmascript/data/objectName.qml8
-rw-r--r--tests/auto/qml/qqmlecmascript/data/objectsCompareAsEqual.qml15
-rw-r--r--tests/auto/qml/qqmlecmascript/data/objectsPassThroughSignals.qml18
-rw-r--r--tests/auto/qml/qqmlecmascript/data/outerBindingOverridesInnerBinding.qml15
-rw-r--r--tests/auto/qml/qqmlecmascript/data/ownership.qml5
-rw-r--r--tests/auto/qml/qqmlecmascript/data/propertyAssignmentErrors.qml29
-rw-r--r--tests/auto/qml/qqmlecmascript/data/propertySplicing.qml10
-rw-r--r--tests/auto/qml/qqmlecmascript/data/propertyVar.1.qml22
-rw-r--r--tests/auto/qml/qqmlecmascript/data/propertyVar.10.qml8
-rw-r--r--tests/auto/qml/qqmlecmascript/data/propertyVar.2.qml24
-rw-r--r--tests/auto/qml/qqmlecmascript/data/propertyVar.3.qml19
-rw-r--r--tests/auto/qml/qqmlecmascript/data/propertyVar.4.qml18
-rw-r--r--tests/auto/qml/qqmlecmascript/data/propertyVar.5.qml18
-rw-r--r--tests/auto/qml/qqmlecmascript/data/propertyVar.6.qml27
-rw-r--r--tests/auto/qml/qqmlecmascript/data/propertyVar.7.qml18
-rw-r--r--tests/auto/qml/qqmlecmascript/data/propertyVar.8.qml12
-rw-r--r--tests/auto/qml/qqmlecmascript/data/propertyVar.9.qml19
-rw-r--r--tests/auto/qml/qqmlecmascript/data/propertyVar.circular.2.qml26
-rw-r--r--tests/auto/qml/qqmlecmascript/data/propertyVar.circular.qml44
-rw-r--r--tests/auto/qml/qqmlecmascript/data/propertyVar.inherit.qml34
-rw-r--r--tests/auto/qml/qqmlecmascript/data/propertyVar.reparent.qml27
-rw-r--r--tests/auto/qml/qqmlecmascript/data/propertyVarCpp.qml17
-rw-r--r--tests/auto/qml/qqmlecmascript/data/propertyVarImplicitOwnership.qml26
-rw-r--r--tests/auto/qml/qqmlecmascript/data/propertyVarOwnership.2.qml24
-rw-r--r--tests/auto/qml/qqmlecmascript/data/propertyVarOwnership.3.qml31
-rw-r--r--tests/auto/qml/qqmlecmascript/data/propertyVarOwnership.3.type.qml5
-rw-r--r--tests/auto/qml/qqmlecmascript/data/propertyVarOwnership.4.qml25
-rw-r--r--tests/auto/qml/qqmlecmascript/data/propertyVarOwnership.4.type1.qml23
-rw-r--r--tests/auto/qml/qqmlecmascript/data/propertyVarOwnership.4.type2.qml6
-rw-r--r--tests/auto/qml/qqmlecmascript/data/propertyVarOwnership.qml22
-rw-r--r--tests/auto/qml/qqmlecmascript/data/qlistqobjectMethods.qml6
-rw-r--r--tests/auto/qml/qqmlecmascript/data/qmlHasOwnProperty.qml72
-rw-r--r--tests/auto/qml/qqmlecmascript/data/qmlToString.qml11
-rw-r--r--tests/auto/qml/qqmlecmascript/data/qobjectConnectionListExceptionHandling.qml24
-rw-r--r--tests/auto/qml/qqmlecmascript/data/qobjectDerivedArgument.qml17
-rw-r--r--tests/auto/qml/qqmlecmascript/data/qtbug_10696.qml26
-rw-r--r--tests/auto/qml/qqmlecmascript/data/qtbug_11600.js1
-rw-r--r--tests/auto/qml/qqmlecmascript/data/qtbug_11600.qml8
-rw-r--r--tests/auto/qml/qqmlecmascript/data/qtbug_11606.qml12
-rw-r--r--tests/auto/qml/qqmlecmascript/data/qtbug_20344.qml6
-rw-r--r--tests/auto/qml/qqmlecmascript/data/qtbug_21580.qml22
-rw-r--r--tests/auto/qml/qqmlecmascript/data/qtbug_21864.js2
-rw-r--r--tests/auto/qml/qqmlecmascript/data/qtbug_21864.qml6
-rw-r--r--tests/auto/qml/qqmlecmascript/data/qtbug_22464.qml15
-rw-r--r--tests/auto/qml/qqmlecmascript/data/qtbug_22679.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/data/qtbug_22843.js5
-rw-r--r--tests/auto/qml/qqmlecmascript/data/qtbug_22843.library.js5
-rw-r--r--tests/auto/qml/qqmlecmascript/data/qtbug_22843.library.qml6
-rw-r--r--tests/auto/qml/qqmlecmascript/data/qtbug_22843.qml6
-rw-r--r--tests/auto/qml/qqmlecmascript/data/qtbug_9792.qml5
-rw-r--r--tests/auto/qml/qqmlecmascript/data/qtcreatorbug_1289.qml13
-rw-r--r--tests/auto/qml/qqmlecmascript/data/readonlyDeclaration.qml45
-rw-r--r--tests/auto/qml/qqmlecmascript/data/realToInt.qml11
-rw-r--r--tests/auto/qml/qqmlecmascript/data/regExp.2.qml7
-rw-r--r--tests/auto/qml/qqmlecmascript/data/regExp.qml7
-rw-r--r--tests/auto/qml/qqmlecmascript/data/remote_file.js2
-rw-r--r--tests/auto/qml/qqmlecmascript/data/rewriteMultiLineStrings.qml35
-rw-r--r--tests/auto/qml/qqmlecmascript/data/rewriteMultiLineStrings_crlf.1.qml13
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceCopy.var.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceCopy.variant.qml15
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceCopyFromJs.var.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceCopyFromJs.variant.qml15
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImport.var.js25
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImport.var.qml18
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImport.variant.js25
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImport.variant.qml18
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportDifferent.var.js19
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportDifferent.var.qml22
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportFail.var.js19
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportFail.var.qml7
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportFail.variant.js19
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportFail.variant.qml8
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportNoBinding.var.js15
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportNoBinding.var.qml12
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportNoBinding.variant.js15
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportNoBinding.variant.qml12
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceCopyNoBinding.var.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceCopyNoBinding.variant.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceDestroyedCopy.var.qml13
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceDestroyedCopy.variant.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceFunction.var.qml23
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceFunction.variant.qml23
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceFunctionFail.var.qml23
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceFunctionFail.variant.qml23
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceMultipleDifferentNoBinding.var.js14
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceMultipleDifferentNoBinding.var.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceMultipleSameNoBinding.var.js15
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceMultipleSameNoBinding.var.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceMultipleSameWithBinding.var.qml12
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceObjectGc.var.qml30
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceSignal.var.qml29
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceSignal.variant.qml29
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceTest.var.js48
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceTest.var.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceTest.variant.js48
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceTest.variant.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceTestMultiple.var.qml16
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceTestMultiple.variant.qml15
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceTestPreserve.var.qml15
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scarceResourceTestPreserve.variant.qml15
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scope.2.qml40
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scope.3.qml13
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scope.4.qml12
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scope.5.qml27
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scope.6.qml10
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scope.qml44
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scriptConnect.1.js4
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scriptConnect.1.qml10
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scriptConnect.2.js5
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scriptConnect.2.qml16
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scriptConnect.3.qml15
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scriptConnect.4.qml12
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scriptConnect.5.qml11
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scriptConnect.6.js3
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scriptConnect.6.qml15
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scriptDisconnect.1.js6
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scriptDisconnect.1.qml13
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scriptDisconnect.2.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scriptDisconnect.3.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scriptDisconnect.4.qml13
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scriptErrors.js4
-rw-r--r--tests/auto/qml/qqmlecmascript/data/scriptErrors.qml18
-rw-r--r--tests/auto/qml/qqmlecmascript/data/selfDeletingBinding.2.qml17
-rw-r--r--tests/auto/qml/qqmlecmascript/data/selfDeletingBinding.qml18
-rw-r--r--tests/auto/qml/qqmlecmascript/data/sequenceConversion.array.qml193
-rw-r--r--tests/auto/qml/qqmlecmascript/data/sequenceConversion.bindings.error.qml19
-rw-r--r--tests/auto/qml/qqmlecmascript/data/sequenceConversion.bindings.qml28
-rw-r--r--tests/auto/qml/qqmlecmascript/data/sequenceConversion.copy.qml160
-rw-r--r--tests/auto/qml/qqmlecmascript/data/sequenceConversion.indexes.qml89
-rw-r--r--tests/auto/qml/qqmlecmascript/data/sequenceConversion.read.error.qml21
-rw-r--r--tests/auto/qml/qqmlecmascript/data/sequenceConversion.read.qml105
-rw-r--r--tests/auto/qml/qqmlecmascript/data/sequenceConversion.threads.qml74
-rw-r--r--tests/auto/qml/qqmlecmascript/data/sequenceConversion.write.error.qml18
-rw-r--r--tests/auto/qml/qqmlecmascript/data/sequenceConversion.write.qml109
-rw-r--r--tests/auto/qml/qqmlecmascript/data/sharedAttachedObject.qml16
-rw-r--r--tests/auto/qml/qqmlecmascript/data/shutdownErrors.qml13
-rw-r--r--tests/auto/qml/qqmlecmascript/data/signalAssignment.1.qml5
-rw-r--r--tests/auto/qml/qqmlecmascript/data/signalAssignment.2.qml5
-rw-r--r--tests/auto/qml/qqmlecmascript/data/signalAssignment.3.qml5
-rw-r--r--tests/auto/qml/qqmlecmascript/data/signalAssignment.4.qml6
-rw-r--r--tests/auto/qml/qqmlecmascript/data/signalHandlers.qml60
-rw-r--r--tests/auto/qml/qqmlecmascript/data/signalParameterTypes.qml18
-rw-r--r--tests/auto/qml/qqmlecmascript/data/signalTriggeredBindings.qml20
-rw-r--r--tests/auto/qml/qqmlecmascript/data/signalWithJSValueInVariant.qml12
-rw-r--r--tests/auto/qml/qqmlecmascript/data/signalWithQJSValue.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/data/signalWithUnknownTypes.qml5
-rw-r--r--tests/auto/qml/qqmlecmascript/data/strictlyEquals.qml17
-rw-r--r--tests/auto/qml/qqmlecmascript/data/stringArg.qml49
-rw-r--r--tests/auto/qml/qqmlecmascript/data/switchStatement.1.qml33
-rw-r--r--tests/auto/qml/qqmlecmascript/data/switchStatement.2.qml33
-rw-r--r--tests/auto/qml/qqmlecmascript/data/switchStatement.3.qml33
-rw-r--r--tests/auto/qml/qqmlecmascript/data/switchStatement.4.qml31
-rw-r--r--tests/auto/qml/qqmlecmascript/data/switchStatement.5.qml12
-rw-r--r--tests/auto/qml/qqmlecmascript/data/switchStatement.6.qml13
-rw-r--r--tests/auto/qml/qqmlecmascript/data/threadScript.js4
-rw-r--r--tests/auto/qml/qqmlecmascript/data/transientErrors.2.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/data/transientErrors.qml10
-rw-r--r--tests/auto/qml/qqmlecmascript/data/tryStatement.1.qml13
-rw-r--r--tests/auto/qml/qqmlecmascript/data/tryStatement.2.qml11
-rw-r--r--tests/auto/qml/qqmlecmascript/data/tryStatement.3.qml13
-rw-r--r--tests/auto/qml/qqmlecmascript/data/tryStatement.4.qml12
-rw-r--r--tests/auto/qml/qqmlecmascript/data/typeOf.js25
-rw-r--r--tests/auto/qml/qqmlecmascript/data/typeOf.qml26
-rw-r--r--tests/auto/qml/qqmlecmascript/data/unaryExpression.qml9
-rw-r--r--tests/auto/qml/qqmlecmascript/data/undefinedResetsProperty.2.qml10
-rw-r--r--tests/auto/qml/qqmlecmascript/data/undefinedResetsProperty.qml7
-rw-r--r--tests/auto/qml/qqmlecmascript/data/urlListProperty.qml41
-rw-r--r--tests/auto/qml/qqmlecmascript/data/urlProperty.1.qml10
-rw-r--r--tests/auto/qml/qqmlecmascript/data/urlProperty.2.qml10
-rw-r--r--tests/auto/qml/qqmlecmascript/data/v8bindingException.qml21
-rw-r--r--tests/auto/qml/qqmlecmascript/data/v8functionException.qml15
-rw-r--r--tests/auto/qml/qqmlecmascript/data/valueTypeFunctions.qml6
-rw-r--r--tests/auto/qml/qqmlecmascript/data/variantsAssignedUndefined.qml9
-rw-r--r--tests/auto/qml/qqmlecmascript/data/withStatement.1.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/data/writeAttachedProperty.qml6
-rw-r--r--tests/auto/qml/qqmlecmascript/data/writeRemovesBinding.qml46
-rw-r--r--tests/auto/qml/qqmlecmascript/qqmlecmascript.pro22
-rw-r--r--tests/auto/qml/qqmlecmascript/testtypes.cpp210
-rw-r--r--tests/auto/qml/qqmlecmascript/testtypes.h1313
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp6097
379 files changed, 14050 insertions, 0 deletions
diff --git a/tests/auto/qml/qqmlecmascript/data/AliasBindingsAssignCorrectlyType.qml b/tests/auto/qml/qqmlecmascript/data/AliasBindingsAssignCorrectlyType.qml
new file mode 100644
index 0000000000..e8e108fa44
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/AliasBindingsAssignCorrectlyType.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+
+QtObject {
+ id: root
+
+ property real realProperty
+ property alias aliasProperty: root.realProperty
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/AliasBindingsOverrideTargetType.qml b/tests/auto/qml/qqmlecmascript/data/AliasBindingsOverrideTargetType.qml
new file mode 100644
index 0000000000..062772106b
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/AliasBindingsOverrideTargetType.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+MyTypeObject {
+ id: root
+
+ property int data: 7
+
+ property int targetProperty: root.data * 43 - root.data
+ property alias aliasProperty: root.targetProperty
+
+ pointProperty: Qt.point(data, data);
+ property alias pointAliasProperty: root.pointProperty
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/AliasBindingsOverrideTargetType3.qml b/tests/auto/qml/qqmlecmascript/data/AliasBindingsOverrideTargetType3.qml
new file mode 100644
index 0000000000..823c0ef367
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/AliasBindingsOverrideTargetType3.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+
+QtObject {
+ id: root
+
+ property int testProperty
+ property alias aliasProperty: root.testProperty
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/AliasToCompositeElementType1.qml b/tests/auto/qml/qqmlecmascript/data/AliasToCompositeElementType1.qml
new file mode 100644
index 0000000000..cef8ae09ea
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/AliasToCompositeElementType1.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+
+QtObject {
+ property alias group: obj
+ property variant foo: AliasToCompositeElementType2 { id: obj }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/AliasToCompositeElementType2.qml b/tests/auto/qml/qqmlecmascript/data/AliasToCompositeElementType2.qml
new file mode 100644
index 0000000000..4a45535a50
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/AliasToCompositeElementType2.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+QtObject {
+ property int value
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/ConstantsOverrideBindings.qml b/tests/auto/qml/qqmlecmascript/data/ConstantsOverrideBindings.qml
new file mode 100644
index 0000000000..07bb16b0d8
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/ConstantsOverrideBindings.qml
@@ -0,0 +1,12 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ property int c1: 0
+ property int c2: c1
+ property alias c3: inner.ic1
+
+ objectProperty: MyQmlObject {
+ id: inner
+ property int ic1: c1
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/CustomObject.qml b/tests/auto/qml/qqmlecmascript/data/CustomObject.qml
new file mode 100644
index 0000000000..aa1a1d6061
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/CustomObject.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+QtObject {
+ property string greeting: "hello world"
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/ElementAssignType.qml b/tests/auto/qml/qqmlecmascript/data/ElementAssignType.qml
new file mode 100644
index 0000000000..4a45535a50
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/ElementAssignType.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+QtObject {
+ property int value
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/MethodsObject.qml b/tests/auto/qml/qqmlecmascript/data/MethodsObject.qml
new file mode 100644
index 0000000000..eaca0a7f92
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/MethodsObject.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+
+QtObject {
+ function testFunction() { return 19; }
+ function testFunction2() { return 18; }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/NestedTypeTransientErrors.qml b/tests/auto/qml/qqmlecmascript/data/NestedTypeTransientErrors.qml
new file mode 100644
index 0000000000..3b3e84a900
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/NestedTypeTransientErrors.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.0
+
+QtObject {
+ property int b: obj.prop.a
+
+ property variant prop;
+ prop: QtObject {
+ property int a: 10
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/PropertyVarBaseItem.qml b/tests/auto/qml/qqmlecmascript/data/PropertyVarBaseItem.qml
new file mode 100644
index 0000000000..5f28833fe7
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/PropertyVarBaseItem.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+Item {
+ property var random: null
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/PropertyVarCircularComponent.qml b/tests/auto/qml/qqmlecmascript/data/PropertyVarCircularComponent.qml
new file mode 100644
index 0000000000..36c025401f
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/PropertyVarCircularComponent.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ id: first
+ property var vp: Item {
+ id: second
+ property var vp: Item {
+ id: third
+ property var vp: Item {
+ id: fourth
+ property var vp: Item {
+ id: fifth
+ property int fifthCanary: 5
+ property var circ: third.vp
+ property MyScarceResourceObject srp;
+ srp: MyScarceResourceObject { id: scarceResourceProvider }
+ property variant memoryHog: scarceResourceProvider.newScarceResource()
+ }
+ }
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/PropertyVarCircularComponent2.qml b/tests/auto/qml/qqmlecmascript/data/PropertyVarCircularComponent2.qml
new file mode 100644
index 0000000000..6a49cb9317
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/PropertyVarCircularComponent2.qml
@@ -0,0 +1,26 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+// Similar to PVCC.qml except that it has another var property
+// It will have a different metaobject.
+Item {
+ id: first
+ property var anotherVp: 6
+ property var vp: Item {
+ id: second
+ property var vp: Item {
+ id: third
+ property var vp: Item {
+ id: fourth
+ property var vp: Item {
+ id: fifth
+ property int fifthCanary: 5
+ property var circ: third.vp
+ property MyScarceResourceObject srp;
+ srp: MyScarceResourceObject { id: scarceResourceProvider }
+ property variant memoryHog2: scarceResourceProvider.newScarceResource()
+ }
+ }
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/PropertyVarCircularComponent3.qml b/tests/auto/qml/qqmlecmascript/data/PropertyVarCircularComponent3.qml
new file mode 100644
index 0000000000..a90725016e
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/PropertyVarCircularComponent3.qml
@@ -0,0 +1,16 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: rectangle // will have JS ownership
+ objectName: "rectangle"
+ width: 10
+ height: 10
+ property var rectCanary: 5
+
+ Text {
+ id: text // will have Eventual-JS ownership
+ objectName: "text"
+ property var vp: rectangle
+ property var textCanary: 10
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/PropertyVarCircularComponent4.qml b/tests/auto/qml/qqmlecmascript/data/PropertyVarCircularComponent4.qml
new file mode 100644
index 0000000000..9273a52f54
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/PropertyVarCircularComponent4.qml
@@ -0,0 +1,28 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: rectangle // will have JS ownership
+ objectName: "rectangle"
+ width: 10
+ height: 10
+ property var rectCanary: 5
+
+ Text {
+ id: text // will have Eventual-JS ownership
+ objectName: "text"
+ property var vp
+ property var textCanary: 10
+
+ // The varProperties array of "text" is weak
+ // (due to eventual JS ownership since parent is JS owned)
+ // but nonetheless, the reference to the created QObject
+ // should cause that QObject to NOT be collected.
+ function constructQObject() {
+ var component = Qt.createComponent("PropertyVarCircularComponent5.qml");
+ if (component.status == Component.Ready) {
+ text.vp = component.createObject(null); // has JavaScript ownership
+ }
+ gc();
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/PropertyVarCircularComponent5.qml b/tests/auto/qml/qqmlecmascript/data/PropertyVarCircularComponent5.qml
new file mode 100644
index 0000000000..94ef338792
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/PropertyVarCircularComponent5.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+Image {
+ id: image
+ objectName: "image"
+ property var imageCanary: 13
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/PropertyVarInheritanceComponent.qml b/tests/auto/qml/qqmlecmascript/data/PropertyVarInheritanceComponent.qml
new file mode 100644
index 0000000000..b01cf6ed84
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/PropertyVarInheritanceComponent.qml
@@ -0,0 +1,22 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+PropertyVarCircularComponent {
+ id: inheritanceComponent
+ property int inheritanceIntProperty: 6
+ property var inheritanceVarProperty
+
+ function constructGarbage() {
+ var retn = 1;
+ var component = Qt.createComponent("PropertyVarCircularComponent2.qml");
+ if (component.status == Component.Ready) {
+ retn = component.createObject(null); // has JavaScript ownership
+ }
+ return retn;
+ }
+
+ Component.onCompleted: {
+ inheritanceVarProperty = constructGarbage();
+ gc();
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/PropertyVarOwnershipComponent.qml b/tests/auto/qml/qqmlecmascript/data/PropertyVarOwnershipComponent.qml
new file mode 100644
index 0000000000..c1f73d3bac
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/PropertyVarOwnershipComponent.qml
@@ -0,0 +1,37 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: rectangle // will have JS ownership
+ objectName: "rectangle"
+ width: 10
+ height: 10
+ property var rectCanary: 5
+
+ Text {
+ id: textOne // will have Eventual-JS ownership
+ objectName: "textOne"
+ property var textCanary: 11
+ property var vp
+ }
+
+ Text {
+ id: textTwo
+ objectName: "textTwo"
+ property var textCanary: 12
+ property var vp
+
+ function constructQObject() {
+ var component = Qt.createComponent("PropertyVarCircularComponent5.qml");
+ if (component.status == Component.Ready) {
+ textTwo.vp = component.createObject(null); // has JavaScript ownership
+ }
+ gc();
+ }
+
+ function deassignVp() {
+ textTwo.textCanary = 22;
+ textTwo.vp = textTwo.textCanary;
+ gc();
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/ScarceResourceSignalComponentVar.qml b/tests/auto/qml/qqmlecmascript/data/ScarceResourceSignalComponentVar.qml
new file mode 100644
index 0000000000..d56bd41a99
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/ScarceResourceSignalComponentVar.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+
+QtObject {
+ property var scarceResourceCopy
+ property int width: 5
+ signal testSignal
+ signal testSignal2
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/ScarceResourceSignalComponentVariant.qml b/tests/auto/qml/qqmlecmascript/data/ScarceResourceSignalComponentVariant.qml
new file mode 100644
index 0000000000..e10fcfe36a
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/ScarceResourceSignalComponentVariant.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+
+QtObject {
+ property variant scarceResourceCopy
+ property int width: 5
+ signal testSignal
+ signal testSignal2
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/ScarceResourceVarComponent.qml b/tests/auto/qml/qqmlecmascript/data/ScarceResourceVarComponent.qml
new file mode 100644
index 0000000000..2cf6b4223b
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/ScarceResourceVarComponent.qml
@@ -0,0 +1,13 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ id: first
+ property var vp: Item {
+ id: second
+ property MyScarceResourceObject srp;
+ srp: MyScarceResourceObject { id: scarceResourceProvider }
+ property var sr: scarceResourceProvider.scarceResource
+ property var canary: 5
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/Scope6Nested.qml b/tests/auto/qml/qqmlecmascript/data/Scope6Nested.qml
new file mode 100644
index 0000000000..a3794df22b
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/Scope6Nested.qml
@@ -0,0 +1,7 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ function runtest(obj) {
+ return obj.MyQmlObject.value == 19;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/ScopeObject.qml b/tests/auto/qml/qqmlecmascript/data/ScopeObject.qml
new file mode 100644
index 0000000000..f341cce3c9
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/ScopeObject.qml
@@ -0,0 +1,12 @@
+import QtQuick 2.0
+
+Item {
+ property int a: 3
+ property int binding: myFunction();
+ property int binding2: myCompFunction();
+
+ function myCompFunction() {
+ return a;
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/SequenceConversionComponent.qml b/tests/auto/qml/qqmlecmascript/data/SequenceConversionComponent.qml
new file mode 100644
index 0000000000..0c7f60b062
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/SequenceConversionComponent.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+MySequenceConversionObject {
+ id: sccmsco
+ objectName: "sccmsco"
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/SpuriousWarning.qml b/tests/auto/qml/qqmlecmascript/data/SpuriousWarning.qml
new file mode 100644
index 0000000000..f6398d254d
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/SpuriousWarning.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+Item {
+ property int children: root.children.length
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/TypeForDynamicCreation.qml b/tests/auto/qml/qqmlecmascript/data/TypeForDynamicCreation.qml
new file mode 100644
index 0000000000..56e06252c4
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/TypeForDynamicCreation.qml
@@ -0,0 +1,2 @@
+import Qt.test 1.0
+MyQmlObject{objectName:"objectThree"}
diff --git a/tests/auto/qml/qqmlecmascript/data/aliasBindingsAssignCorrectly.qml b/tests/auto/qml/qqmlecmascript/data/aliasBindingsAssignCorrectly.qml
new file mode 100644
index 0000000000..ff6c553c31
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/aliasBindingsAssignCorrectly.qml
@@ -0,0 +1,59 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+
+ property bool test: false
+
+ property real testData: 9
+ property real testData2: 9
+
+ states: State {
+ name: "change"
+ PropertyChanges {
+ target: myType
+ realProperty: if (testData2 > 3) 9; else 11;
+ }
+ }
+
+ AliasBindingsAssignCorrectlyType {
+ id: myType
+
+ aliasProperty: if (testData > 3) 14; else 12;
+ }
+
+ Component.onCompleted: {
+ // Check original binding works
+ if (myType.aliasProperty != 14) return;
+
+ testData = 2;
+ if (myType.aliasProperty != 12) return;
+
+ // Change binding indirectly by modifying the "realProperty"
+ root.state = "change";
+ if (myType.aliasProperty != 9) return;
+
+ // Check the new binding works
+ testData2 = 1;
+ if (myType.aliasProperty != 11) return;
+
+ // Try and trigger the old binding (that should have been removed)
+ testData = 6;
+ if (myType.aliasProperty != 11) return;
+
+ // Restore the original binding
+ root.state = "";
+ if (myType.aliasProperty != 14) return;
+
+ // Test the restored binding works
+ testData = 0;
+ if (myType.aliasProperty != 12) return;
+
+ // Test the old binding isn't somehow hanging around and still in effect
+ testData2 = 13;
+ if (myType.aliasProperty != 12) return;
+
+ test = true;
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/aliasBindingsOverrideTarget.2.qml b/tests/auto/qml/qqmlecmascript/data/aliasBindingsOverrideTarget.2.qml
new file mode 100644
index 0000000000..bba9033235
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/aliasBindingsOverrideTarget.2.qml
@@ -0,0 +1,29 @@
+import QtQuick 2.0
+
+Item {
+ id: me
+ property bool test: false
+
+ property int value: 9
+
+ AliasBindingsOverrideTargetType {
+ id: aliasType
+ pointAliasProperty.x: me.value
+ }
+
+ Component.onCompleted: {
+ if (aliasType.pointAliasProperty.x != 9) return;
+
+ me.value = 11;
+ if (aliasType.pointAliasProperty.x != 11) return;
+
+ aliasType.data = 8;
+ if (aliasType.pointAliasProperty.x != 11) return;
+
+ me.value = 4;
+ if (aliasType.pointAliasProperty.x != 4) return;
+
+ test = true;
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/aliasBindingsOverrideTarget.3.qml b/tests/auto/qml/qqmlecmascript/data/aliasBindingsOverrideTarget.3.qml
new file mode 100644
index 0000000000..3e4cda6ba3
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/aliasBindingsOverrideTarget.3.qml
@@ -0,0 +1,24 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+ property bool test: false;
+
+ property int value1: 10
+ property int value2: 11
+
+ AliasBindingsOverrideTargetType3 {
+ id: obj
+
+ testProperty: root.value1 * 9
+ aliasProperty: root.value2 * 10
+ }
+
+ Component.onCompleted: {
+ if (obj.testProperty != 110) return;
+ if (obj.aliasProperty != 110) return;
+
+ test = true;
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/aliasBindingsOverrideTarget.qml b/tests/auto/qml/qqmlecmascript/data/aliasBindingsOverrideTarget.qml
new file mode 100644
index 0000000000..de5f49ffc5
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/aliasBindingsOverrideTarget.qml
@@ -0,0 +1,28 @@
+import QtQuick 2.0
+
+Item {
+ id: me
+ property bool test: false
+
+ property int value: 9
+
+ AliasBindingsOverrideTargetType {
+ id: aliasType
+ aliasProperty: me.value
+ }
+
+ Component.onCompleted: {
+ if (aliasType.aliasProperty != 9) return;
+
+ me.value = 11;
+ if (aliasType.aliasProperty != 11) return;
+
+ aliasType.data = 8;
+ if (aliasType.aliasProperty != 11) return;
+
+ me.value = 4;
+ if (aliasType.aliasProperty != 4) return;
+
+ test = true;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/aliasPropertyAndBinding.qml b/tests/auto/qml/qqmlecmascript/data/aliasPropertyAndBinding.qml
new file mode 100644
index 0000000000..f228b2c19f
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/aliasPropertyAndBinding.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+MyQmlObject {
+ property alias c1: myObject.c1
+ property int c2: 3
+ property int c3: c2
+ objectProperty: QtObject {
+ id: myObject
+ property int c1
+ }
+}
+
+
diff --git a/tests/auto/qml/qqmlecmascript/data/aliasToCompositeElement.qml b/tests/auto/qml/qqmlecmascript/data/aliasToCompositeElement.qml
new file mode 100644
index 0000000000..79d6e6887c
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/aliasToCompositeElement.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+
+AliasToCompositeElementType1 {
+ group.value: 13
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/aliasWritesOverrideBindings.2.qml b/tests/auto/qml/qqmlecmascript/data/aliasWritesOverrideBindings.2.qml
new file mode 100644
index 0000000000..b5bc280d11
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/aliasWritesOverrideBindings.2.qml
@@ -0,0 +1,29 @@
+import QtQuick 2.0
+
+Item {
+ id: me
+ property bool test: false
+
+ property int value: 9
+
+ AliasBindingsOverrideTargetType {
+ id: aliasType
+ }
+
+ Component.onCompleted: {
+ if (aliasType.aliasProperty != 294) return;
+
+ aliasType.data = 8;
+ if (aliasType.aliasProperty != 336) return;
+
+ aliasType.aliasProperty = 4;
+ if (aliasType.aliasProperty != 4) return;
+
+ aliasType.data = 7;
+ if (aliasType.aliasProperty != 4) return;
+
+ test = true;
+ }
+}
+
+
diff --git a/tests/auto/qml/qqmlecmascript/data/aliasWritesOverrideBindings.3.qml b/tests/auto/qml/qqmlecmascript/data/aliasWritesOverrideBindings.3.qml
new file mode 100644
index 0000000000..6c16ff5604
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/aliasWritesOverrideBindings.3.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.0
+
+Item {
+ id: me
+ property bool test: false
+
+ property int value: 9
+
+ AliasBindingsOverrideTargetType {
+ id: aliasType
+ pointAliasProperty.x: 9
+ }
+
+ Component.onCompleted: {
+ if (aliasType.pointAliasProperty.x != 9) return;
+
+ aliasType.data = 8;
+ if (aliasType.pointAliasProperty.x != 9) return;
+
+ test = true;
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/aliasWritesOverrideBindings.qml b/tests/auto/qml/qqmlecmascript/data/aliasWritesOverrideBindings.qml
new file mode 100644
index 0000000000..441098bd39
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/aliasWritesOverrideBindings.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.0
+
+Item {
+ id: me
+ property bool test: false
+
+ property int value: 9
+
+ AliasBindingsOverrideTargetType {
+ id: aliasType
+ aliasProperty: 11
+ }
+
+ Component.onCompleted: {
+ if (aliasType.aliasProperty != 11) return;
+
+ aliasType.data = 8;
+ if (aliasType.aliasProperty != 11) return;
+
+ test = true;
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/aliasreset/AliasPropertyComponent.qml b/tests/auto/qml/qqmlecmascript/data/aliasreset/AliasPropertyComponent.qml
new file mode 100644
index 0000000000..9135e79469
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/aliasreset/AliasPropertyComponent.qml
@@ -0,0 +1,17 @@
+import QtQuick 2.0
+
+Item {
+ id: apc
+ property alias sourceComponent: loader.sourceComponent
+
+ Component {
+ id: redSquare
+ Rectangle { color: "red"; width: 10; height: 10 }
+ }
+
+ Loader {
+ id: loader
+ objectName: "loader"
+ sourceComponent: redSquare
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/aliasreset/aliasPropertyReset.1.qml b/tests/auto/qml/qqmlecmascript/data/aliasreset/aliasPropertyReset.1.qml
new file mode 100644
index 0000000000..b855a183ee
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/aliasreset/aliasPropertyReset.1.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ id: first
+ property bool aliasIsUndefined: false
+ property alias sourceComponentAlias: loader.sourceComponent
+
+ Component {
+ id: redSquare
+ Rectangle { color: "red"; width: 10; height: 10 }
+ }
+
+ Loader {
+ id: loader
+ sourceComponent: redSquare
+ }
+
+ function resetAliased() {
+ loader.sourceComponent = undefined;
+ aliasIsUndefined = (sourceComponentAlias == undefined);
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/aliasreset/aliasPropertyReset.2.qml b/tests/auto/qml/qqmlecmascript/data/aliasreset/aliasPropertyReset.2.qml
new file mode 100644
index 0000000000..b0bb3681cf
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/aliasreset/aliasPropertyReset.2.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ id: first
+ property bool loaderSourceComponentIsUndefined: false
+ property alias sourceComponentAlias: loader.sourceComponent
+
+ Component {
+ id: redSquare
+ Rectangle { color: "red"; width: 10; height: 10 }
+ }
+
+ Loader {
+ id: loader
+ sourceComponent: redSquare
+ }
+
+ function resetAlias() {
+ sourceComponentAlias = undefined;
+ loaderSourceComponentIsUndefined = (loader.sourceComponent == undefined);
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/aliasreset/aliasPropertyReset.3.qml b/tests/auto/qml/qqmlecmascript/data/aliasreset/aliasPropertyReset.3.qml
new file mode 100644
index 0000000000..b318af0138
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/aliasreset/aliasPropertyReset.3.qml
@@ -0,0 +1,31 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ id: first
+ property bool loaderTwoSourceComponentIsUndefined: false
+ property bool loaderOneSourceComponentIsUndefined: false
+ property alias sourceComponentAlias: loaderOne.sourceComponent
+
+ Component {
+ id: redSquare
+ Rectangle { color: "red"; width: 10; height: 10 }
+ }
+
+ Loader {
+ id: loaderOne
+ sourceComponent: loaderTwo.sourceComponent
+ }
+
+ Loader {
+ id: loaderTwo
+ sourceComponent: redSquare
+ x: 15
+ }
+
+ function resetAlias() {
+ sourceComponentAlias = undefined; // loaderOne.sourceComponent should be set to undefined instead of l2.sc
+ loaderOneSourceComponentIsUndefined = (loaderOne.sourceComponent == undefined); // should be true
+ loaderTwoSourceComponentIsUndefined = (loaderTwo.sourceComponent == undefined); // should be false
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/aliasreset/aliasPropertyReset.4.qml b/tests/auto/qml/qqmlecmascript/data/aliasreset/aliasPropertyReset.4.qml
new file mode 100644
index 0000000000..c5f56a8798
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/aliasreset/aliasPropertyReset.4.qml
@@ -0,0 +1,26 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ id: first
+ property alias sourceComponentAlias: loader.sourceComponent
+
+ Component {
+ id: redSquare
+ Rectangle { color: "red"; width: 10; height: 10 }
+ }
+
+ Loader {
+ id: loader
+ objectName: "loader"
+ sourceComponent: redSquare
+ }
+
+ function resetAlias() {
+ sourceComponentAlias = undefined; // ensure we don't crash after deletion of loader.
+ }
+
+ function setAlias() {
+ sourceComponentAlias = redSquare;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/aliasreset/aliasPropertyReset.5.qml b/tests/auto/qml/qqmlecmascript/data/aliasreset/aliasPropertyReset.5.qml
new file mode 100644
index 0000000000..b07db8ba40
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/aliasreset/aliasPropertyReset.5.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ id: root
+
+ AliasPropertyComponent {
+ sourceComponent: returnsUndefined()
+ }
+
+ function returnsUndefined() {
+ return undefined;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/aliasreset/aliasPropertyReset.error.1.qml b/tests/auto/qml/qqmlecmascript/data/aliasreset/aliasPropertyReset.error.1.qml
new file mode 100644
index 0000000000..35c9d6fd5d
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/aliasreset/aliasPropertyReset.error.1.qml
@@ -0,0 +1,18 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+MyQmlObject {
+ id: first
+ property bool aliasedIntIsUndefined: false
+ property alias intAlias: objprop.intp
+
+ objectProperty: QtObject {
+ id: objprop
+ property int intp: 12
+ }
+
+ function resetAlias() {
+ intAlias = undefined; // should error
+ aliasedIntIsUndefined = (objprop.intp == undefined);
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/assignBasicTypes.2.qml b/tests/auto/qml/qqmlecmascript/data/assignBasicTypes.2.qml
new file mode 100644
index 0000000000..2c79729651
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/assignBasicTypes.2.qml
@@ -0,0 +1,26 @@
+import Qt.test 1.0
+
+MyTypeObject {
+ flagProperty: if(1) "FlagVal1 | FlagVal3"
+ enumProperty: if(1) "EnumVal2"
+ stringProperty: if(1) "Hello World!"
+ uintProperty: if(1) 10
+ intProperty: if(1) -19
+ realProperty: if(1) 23.2
+ doubleProperty: if(1) -19.75
+ floatProperty: if(1) 8.5
+ colorProperty: if(1) "red"
+ dateProperty: if(1) "1982-11-25"
+ timeProperty: if(1) "11:11:32"
+ dateTimeProperty: if(1) "2009-05-12T13:22:01"
+ pointProperty: if(1) "99,13"
+ pointFProperty: if(1) "-10.1,12.3"
+ sizeProperty: if(1) "99x13"
+ sizeFProperty: if(1) "0.1x0.2"
+ rectProperty: if(1) "9,7,100x200"
+ rectFProperty: if(1) "1000.1,-10.9,400x90.99"
+ boolProperty: if(1) true
+ variantProperty: if(1) "Hello World!"
+ vectorProperty: if(1) "10,1,2.2"
+ urlProperty: if(1) "main.qml"
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/assignBasicTypes.qml b/tests/auto/qml/qqmlecmascript/data/assignBasicTypes.qml
new file mode 100644
index 0000000000..86ff6b6bb3
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/assignBasicTypes.qml
@@ -0,0 +1,29 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+MyTypeObject {
+ Component.onCompleted: {
+ flagProperty = "FlagVal1 | FlagVal3"
+ enumProperty = "EnumVal2"
+ stringProperty = "Hello World!"
+ uintProperty = 10
+ intProperty = -19
+ realProperty = 23.2
+ doubleProperty = -19.75
+ floatProperty = 8.5
+ colorProperty = "red"
+ dateProperty = "1982-11-25"
+ timeProperty = "11:11:32"
+ dateTimeProperty = "2009-05-12T13:22:01"
+ pointProperty = "99,13"
+ pointFProperty = "-10.1,12.3"
+ sizeProperty = "99x13"
+ sizeFProperty = "0.1x0.2"
+ rectProperty = "9,7,100x200"
+ rectFProperty = "1000.1,-10.9,400x90.99"
+ boolProperty = true
+ variantProperty = "Hello World!"
+ vectorProperty = "10,1,2.2"
+ urlProperty = "main.qml"
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.1.qml b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.1.qml
new file mode 100644
index 0000000000..be283fdda1
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.1.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+MySequenceConversionObject {
+ intListProperty: [1, 2]
+ qrealListProperty: [1.1, 2.2]
+ boolListProperty: [false, true]
+ urlListProperty: [ "http://www.example1.com", "http://www.example2.com" ]
+ stringListProperty: [ "one", "two" ]
+ qstringListProperty: [ "one", "two" ]
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.2.qml b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.2.qml
new file mode 100644
index 0000000000..c8fb28b04e
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.2.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+MySequenceConversionObject {
+ intListProperty: 1
+ qrealListProperty: 1.1
+ boolListProperty: false
+ urlListProperty: "http://www.example1.com"
+ stringListProperty: "one"
+ qstringListProperty: "two"
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.3.qml b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.3.qml
new file mode 100644
index 0000000000..ad8a92e317
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.3.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+MySequenceConversionObject {
+ intListProperty: 1
+ qrealListProperty: 1.1
+ boolListProperty: false
+ urlListProperty: Qt.resolvedUrl("example.html")
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.4.qml b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.4.qml
new file mode 100644
index 0000000000..a9f2e642d1
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.4.qml
@@ -0,0 +1,13 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+MySequenceConversionObject {
+ Component.onCompleted: {
+ intListProperty = [1, 2]
+ qrealListProperty = [1.1, 2.2]
+ boolListProperty = [false, true]
+ urlListProperty = [ "http://www.example1.com", "http://www.example2.com" ]
+ stringListProperty = [ "one", "two" ]
+ qstringListProperty = [ "one", "two" ]
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.5.qml b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.5.qml
new file mode 100644
index 0000000000..b8697e4290
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.5.qml
@@ -0,0 +1,13 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+MySequenceConversionObject {
+ Component.onCompleted: {
+ intListProperty = 1;
+ qrealListProperty = 1.1;
+ boolListProperty = false;
+ urlListProperty = "http://www.example1.com";
+ stringListProperty = "one";
+ qstringListProperty = "two";
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.6.qml b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.6.qml
new file mode 100644
index 0000000000..7a794eb694
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.6.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+MySequenceConversionObject {
+ Component.onCompleted: {
+ intListProperty = 1;
+ qrealListProperty = 1.1;
+ boolListProperty = false;
+ urlListProperty = Qt.resolvedUrl("example.html");
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.7.qml b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.7.qml
new file mode 100644
index 0000000000..96c0684939
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/assignSequenceTypes.7.qml
@@ -0,0 +1,42 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ // single url assignment to url list property
+ MySequenceConversionObject {
+ id: msco1
+ objectName: "msco1"
+ }
+
+ // single url binding to url list property
+ MySequenceConversionObject {
+ id: msco2
+ objectName: "msco2"
+ urlListProperty: "example.html"
+ }
+
+ // multiple url assignment to url list property
+ MySequenceConversionObject {
+ id: msco3
+ objectName: "msco3"
+ }
+
+ // multiple url binding to url list property
+ MySequenceConversionObject {
+ id: msco4
+ objectName: "msco4"
+ urlListProperty: [ "example.html", "example2.html" ]
+ }
+
+ // multiple url binding to url list property - already resolved
+ MySequenceConversionObject {
+ id: msco5
+ objectName: "msco5"
+ urlListProperty: [ Qt.resolvedUrl("example.html"), Qt.resolvedUrl("example2.html") ]
+ }
+
+ Component.onCompleted: {
+ msco1.urlListProperty = "example.html";
+ msco3.urlListProperty = [ "example.html", "example2.html" ];
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/attachedProperty.2.qml b/tests/auto/qml/qqmlecmascript/data/attachedProperty.2.qml
new file mode 100644
index 0000000000..a7184c9200
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/attachedProperty.2.qml
@@ -0,0 +1,22 @@
+import Qt.test 1.0
+import Qt.test 1.0 as Namespace
+
+MyQmlObject {
+ property alias a: me.a
+ property alias b: me.a
+ property alias c: me.a
+ property alias d: me.a
+
+ property MyQmlObject obj
+ obj: MyQmlObject {
+ MyQmlObject.value2: 13
+
+ id: me
+ property int a: MyQmlObject.value2 * 2
+ property int b: Namespace.MyQmlObject.value2 * 2
+ property int c: me.Namespace.MyQmlObject.value * 2
+ property int d: me.Namespace.MyQmlObject.value * 2
+ }
+}
+
+
diff --git a/tests/auto/qml/qqmlecmascript/data/attachedProperty.qml b/tests/auto/qml/qqmlecmascript/data/attachedProperty.qml
new file mode 100644
index 0000000000..061eda0e54
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/attachedProperty.qml
@@ -0,0 +1,11 @@
+import Qt.test 1.0
+import Qt.test 1.0 as Namespace
+
+MyQmlObject {
+ id: me
+ property int a: MyQmlObject.value
+ property int b: Namespace.MyQmlObject.value
+ property int c: me.Namespace.MyQmlObject.value
+ property int d: me.Namespace.MyQmlObject.value
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/attachedPropertyScope.qml b/tests/auto/qml/qqmlecmascript/data/attachedPropertyScope.qml
new file mode 100644
index 0000000000..11fb7ccad2
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/attachedPropertyScope.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+QtObject {
+ property int value: 9
+ property int value2
+
+ MyQmlObject.onMySignal: value2 = value
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/automaticSemicolon.qml b/tests/auto/qml/qqmlecmascript/data/automaticSemicolon.qml
new file mode 100644
index 0000000000..6db68f2328
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/automaticSemicolon.qml
@@ -0,0 +1,11 @@
+
+import QtQuick 2.0
+
+QtObject {
+ function code() {
+ if (1) {
+ var a;
+ function f1(){}a=1;
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/bindingLoop.qml b/tests/auto/qml/qqmlecmascript/data/bindingLoop.qml
new file mode 100644
index 0000000000..80545cf72b
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/bindingLoop.qml
@@ -0,0 +1,14 @@
+import Qt.test 1.0
+
+MyQmlContainer {
+ children : [
+ MyQmlObject {
+ id: object1
+ stringProperty: "hello" + object2.stringProperty
+ },
+ MyQmlObject {
+ id: object2
+ stringProperty: "hello" + object1.stringProperty
+ }
+ ]
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/blank.js b/tests/auto/qml/qqmlecmascript/data/blank.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/blank.js
diff --git a/tests/auto/qml/qqmlecmascript/data/boolPropertiesEvaluateAsBool.1.qml b/tests/auto/qml/qqmlecmascript/data/boolPropertiesEvaluateAsBool.1.qml
new file mode 100644
index 0000000000..3147f63989
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/boolPropertiesEvaluateAsBool.1.qml
@@ -0,0 +1,5 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ stringProperty: trueProperty?'pass':'fail'
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/boolPropertiesEvaluateAsBool.2.qml b/tests/auto/qml/qqmlecmascript/data/boolPropertiesEvaluateAsBool.2.qml
new file mode 100644
index 0000000000..c89bb49b45
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/boolPropertiesEvaluateAsBool.2.qml
@@ -0,0 +1,5 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ stringProperty: falseProperty?'fail':'pass'
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/booleanConversion.qml b/tests/auto/qml/qqmlecmascript/data/booleanConversion.qml
new file mode 100644
index 0000000000..a363cf4dd1
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/booleanConversion.qml
@@ -0,0 +1,28 @@
+import QtQuick 2.0
+
+QtObject {
+ id: root
+
+ property bool test_true1: false
+ property bool test_true2: false
+ property bool test_true3: false
+ property bool test_true4: false
+ property bool test_true5: false
+
+ property bool test_false1: true
+ property bool test_false2: true
+ property bool test_false3: true
+
+
+ Component.onCompleted: {
+ test_true1 = 11
+ test_true2 = "Hello"
+ test_true3 = root
+ test_true4 = { a: 10, b: 11 }
+ test_true5 = true
+
+ test_false1 = 0
+ test_false2 = null
+ test_false3 = false
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/bug.1.qml b/tests/auto/qml/qqmlecmascript/data/bug.1.qml
new file mode 100644
index 0000000000..31f7c44fcc
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/bug.1.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.0
+
+QtObject {
+ property int a: 10
+ property bool b: false
+
+ property int test
+
+ test: ((a == 10)?(a + 1):0) + ((b == true)?9:3)
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/canAssignNullToQObject.1.qml b/tests/auto/qml/qqmlecmascript/data/canAssignNullToQObject.1.qml
new file mode 100644
index 0000000000..3fd9131b2f
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/canAssignNullToQObject.1.qml
@@ -0,0 +1,9 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ property bool runTest: false
+
+ property variant a: MyQmlObject {}
+
+ objectProperty: (runTest == false)?a:null
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/canAssignNullToQObject.2.qml b/tests/auto/qml/qqmlecmascript/data/canAssignNullToQObject.2.qml
new file mode 100644
index 0000000000..3fbf931fca
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/canAssignNullToQObject.2.qml
@@ -0,0 +1,11 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+MyQmlObject {
+ objectProperty: MyQmlObject {}
+
+ Component.onCompleted: {
+ objectProperty = null;
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/changeslots/propertyChangeSlotErrors.1.qml b/tests/auto/qml/qqmlecmascript/data/changeslots/propertyChangeSlotErrors.1.qml
new file mode 100644
index 0000000000..1e92aca825
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/changeslots/propertyChangeSlotErrors.1.qml
@@ -0,0 +1,12 @@
+import QtQuick 2.0
+
+Item {
+ property int changeCount: 0
+
+ property bool _nameWithUnderscore: false
+
+ // this should error, since the first alpha isn't capitalised.
+ on_nameWithUnderscoreChanged: {
+ changeCount = changeCount + 2;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/changeslots/propertyChangeSlotErrors.2.qml b/tests/auto/qml/qqmlecmascript/data/changeslots/propertyChangeSlotErrors.2.qml
new file mode 100644
index 0000000000..3549d8c556
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/changeslots/propertyChangeSlotErrors.2.qml
@@ -0,0 +1,12 @@
+import QtQuick 2.0
+
+Item {
+ property int changeCount: 0
+
+ property bool ____nameWithUnderscores: false
+
+ // this should error, since the first alpha isn't capitalised
+ on____nameWithUnderscoresChanged: {
+ changeCount = changeCount + 3;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/changeslots/propertyChangeSlotErrors.3.qml b/tests/auto/qml/qqmlecmascript/data/changeslots/propertyChangeSlotErrors.3.qml
new file mode 100644
index 0000000000..d611e0fe30
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/changeslots/propertyChangeSlotErrors.3.qml
@@ -0,0 +1,12 @@
+import QtQuick 2.0
+
+Item {
+ property int changeCount: 0
+
+ // invalid property name - we don't allow $
+ property bool $nameWithDollarsign: false
+
+ on$NameWithDollarsignChanged: {
+ changeCount = changeCount + 4;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/changeslots/propertyChangeSlotErrors.4.qml b/tests/auto/qml/qqmlecmascript/data/changeslots/propertyChangeSlotErrors.4.qml
new file mode 100644
index 0000000000..a6862517c6
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/changeslots/propertyChangeSlotErrors.4.qml
@@ -0,0 +1,12 @@
+import QtQuick 2.0
+
+Item {
+ property int changeCount: 0
+
+ property bool _6nameWithUnderscoreNumber: false
+
+ // invalid property name - the first character after an underscore must be a letter
+ on_6NameWithUnderscoreNumberChanged: {
+ changeCount = changeCount + 3;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/changeslots/propertyChangeSlots.qml b/tests/auto/qml/qqmlecmascript/data/changeslots/propertyChangeSlots.qml
new file mode 100644
index 0000000000..f91fb71f1f
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/changeslots/propertyChangeSlots.qml
@@ -0,0 +1,27 @@
+import QtQuick 2.0
+
+Item {
+ property int changeCount: 0
+
+ property bool normalName: false
+ property bool _nameWithUnderscore: false
+ property bool ____nameWithUnderscores: false
+
+ onNormalNameChanged: {
+ changeCount = changeCount + 1;
+ }
+
+ on_NameWithUnderscoreChanged: {
+ changeCount = changeCount + 2;
+ }
+
+ on____NameWithUnderscoresChanged: {
+ changeCount = changeCount + 3;
+ }
+
+ Component.onCompleted: {
+ normalName = true;
+ _nameWithUnderscore = true;
+ ____nameWithUnderscores = true;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/compiled.qml b/tests/auto/qml/qqmlecmascript/data/compiled.qml
new file mode 100644
index 0000000000..7c46306772
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/compiled.qml
@@ -0,0 +1,48 @@
+import QtQuick 2.0
+
+QtObject {
+ //real
+ property real test1: a + b
+ property real test2: a - b
+ property bool test3: (a < b)
+ property bool test4: (a > b)
+ property bool test5: (a == b)
+ property bool test6: (a != b)
+
+ //int
+ property int test7: c + d
+ property int test8: d - c
+ property bool test9: (c < d)
+ property bool test10: (c > d)
+ property bool test11: (c == d)
+ property bool test12: (c != d)
+
+ //string
+ property string test13: e + f
+ property string test14: e + " " + f
+ property bool test15: (e == f)
+ property bool test16: (e != f)
+
+ //type conversion
+ property int test17: a
+ property real test18: d
+ property int test19: g
+ property real test20: g
+ property string test21: g
+ property string test22: h
+ property bool test23: i
+ property color test24: j
+ property color test25: k
+
+ property real a: 4.5
+ property real b: 11.2
+ property int c: 9
+ property int d: 176
+ property string e: "Hello"
+ property string f: "World"
+ property variant g: 6.7
+ property variant h: "!"
+ property variant i: true
+ property string j: "#112233"
+ property string k: "#aa112233"
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/compositePropertyType.qml b/tests/auto/qml/qqmlecmascript/data/compositePropertyType.qml
new file mode 100644
index 0000000000..e97b75c8d0
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/compositePropertyType.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+
+QtObject {
+ property CustomObject myObject
+ myObject: CustomObject { }
+
+ Component.onCompleted: console.log(myObject.greeting)
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/constantsOverrideBindings.1.qml b/tests/auto/qml/qqmlecmascript/data/constantsOverrideBindings.1.qml
new file mode 100644
index 0000000000..13c5ae5fff
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/constantsOverrideBindings.1.qml
@@ -0,0 +1,8 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ property int c1: 0
+ property int c2: c1
+
+ onBasicSignal: c2 = 13
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/constantsOverrideBindings.2.qml b/tests/auto/qml/qqmlecmascript/data/constantsOverrideBindings.2.qml
new file mode 100644
index 0000000000..207a06b700
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/constantsOverrideBindings.2.qml
@@ -0,0 +1,11 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ property alias c1: myConstants.c1
+ property alias c2: myConstants.c2
+
+ objectProperty: ConstantsOverrideBindings {
+ id: myConstants
+ c2: 10
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/constantsOverrideBindings.3.qml b/tests/auto/qml/qqmlecmascript/data/constantsOverrideBindings.3.qml
new file mode 100644
index 0000000000..ca9d1d8ab9
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/constantsOverrideBindings.3.qml
@@ -0,0 +1,7 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ property int c1: 0
+ property int c2: c1
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/constantsOverrideBindings.4.qml b/tests/auto/qml/qqmlecmascript/data/constantsOverrideBindings.4.qml
new file mode 100644
index 0000000000..5a2091f71c
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/constantsOverrideBindings.4.qml
@@ -0,0 +1,11 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ property alias c1: myConstants.c1
+ property alias c3: myConstants.c3
+
+ objectProperty: ConstantsOverrideBindings {
+ id: myConstants
+ c3: 10
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/deferredProperties.qml b/tests/auto/qml/qqmlecmascript/data/deferredProperties.qml
new file mode 100644
index 0000000000..e01f708a07
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/deferredProperties.qml
@@ -0,0 +1,10 @@
+import Qt.test 1.0
+
+MyDeferredObject {
+ id: root
+ value: 10
+ objectProperty: MyQmlObject {
+ value: root.value
+ }
+ objectProperty2: MyQmlObject { id: blah }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/deferredPropertiesErrors.qml b/tests/auto/qml/qqmlecmascript/data/deferredPropertiesErrors.qml
new file mode 100644
index 0000000000..308a01ce6f
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/deferredPropertiesErrors.qml
@@ -0,0 +1,10 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+MyDeferredObject {
+ value: undefined // error is resolved before complete
+ objectProperty: undefined // immediate error
+ objectProperty2: QtObject {
+ Component.onCompleted: value = 10
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/deleteLater.qml b/tests/auto/qml/qqmlecmascript/data/deleteLater.qml
new file mode 100644
index 0000000000..2a9ce44b20
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/deleteLater.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+
+QtObject {
+ id: root
+ property bool test: false
+
+ Component.onCompleted: {
+ try {
+ root.deleteLater()
+ } catch(e) {
+ test = true;
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/deleteWhileBindingRunning.qml b/tests/auto/qml/qqmlecmascript/data/deleteWhileBindingRunning.qml
new file mode 100644
index 0000000000..b5cc59e2c0
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/deleteWhileBindingRunning.qml
@@ -0,0 +1,5 @@
+import Qt.test 1.0
+
+MyDeleteObject {
+ property int result: nestedObject.intProperty + deleteNestedObject
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/deletedEngine.qml b/tests/auto/qml/qqmlecmascript/data/deletedEngine.qml
new file mode 100644
index 0000000000..97acddf5fc
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/deletedEngine.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.0
+
+QtObject {
+ function calculate() {
+ return b * 13;
+ }
+
+ property int a: calculate()
+ property int b: 3
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/deletedObject.qml b/tests/auto/qml/qqmlecmascript/data/deletedObject.qml
new file mode 100644
index 0000000000..24c12bf694
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/deletedObject.qml
@@ -0,0 +1,25 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+QtObject {
+ property variant obj
+ obj: MyQmlObject {
+ id: myObject
+ value: 92
+ }
+
+ property bool test1: false
+ property bool test2: false
+ property bool test3: false
+ property bool test4: false
+
+ Component.onCompleted: {
+ test1 = myObject.value == 92;
+ test2 = obj.value == 92;
+
+ myObject.deleteOnSet = 1;
+
+ test3 = myObject == null
+ test4 = obj == null
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/doubleEvaluate.qml b/tests/auto/qml/qqmlecmascript/data/doubleEvaluate.qml
new file mode 100644
index 0000000000..0532715432
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/doubleEvaluate.qml
@@ -0,0 +1,6 @@
+import Qt.test 1.0
+
+WriteCounter {
+ property int x: 0
+ value: if (1) x + x
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/dynamicCreation.helper.qml b/tests/auto/qml/qqmlecmascript/data/dynamicCreation.helper.qml
new file mode 100644
index 0000000000..d790d634e9
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/dynamicCreation.helper.qml
@@ -0,0 +1,6 @@
+import Qt.test 1.0
+
+MyQmlObject{
+ objectName: "objectTwo"
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/dynamicCreation.qml b/tests/auto/qml/qqmlecmascript/data/dynamicCreation.qml
new file mode 100644
index 0000000000..7b132e1edf
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/dynamicCreation.qml
@@ -0,0 +1,27 @@
+import Qt.test 1.0
+
+MyQmlObject{
+ id: obj
+ objectName: "obj"
+ function createOne()
+ {
+ obj.objectProperty = Qt.createQmlObject('import Qt.test 1.0; MyQmlObject{objectName:"objectOne"}', obj);
+ }
+
+ function createTwo()
+ {
+ var component = Qt.createComponent('dynamicCreation.helper.qml');
+ obj.objectProperty = component.createObject(obj);
+ }
+
+ function createThree()
+ {
+ obj.objectProperty = Qt.createQmlObject('TypeForDynamicCreation{}', obj);
+ }
+
+ function dontCrash()
+ {
+ var component = Qt.createComponent('file-doesnt-exist.qml');
+ obj.objectProperty = component.createObject(obj);
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/dynamicCreationOwnership.qml b/tests/auto/qml/qqmlecmascript/data/dynamicCreationOwnership.qml
new file mode 100644
index 0000000000..ed396d49b0
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/dynamicCreationOwnership.qml
@@ -0,0 +1,20 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ id: obj
+ objectName: "obj"
+
+ MyDynamicCreationDestructionObject {
+ id: mdcdo
+ objectName: "mdcdo"
+ }
+
+ function dynamicallyCreateJsOwnedObject() {
+ mdcdo.createNew();
+ }
+
+ function performGc() {
+ gc();
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/dynamicDeletion.2.qml b/tests/auto/qml/qqmlecmascript/data/dynamicDeletion.2.qml
new file mode 100644
index 0000000000..9a5732c194
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/dynamicDeletion.2.qml
@@ -0,0 +1,21 @@
+import QtQuick 2.0
+
+QtObject {
+ id: root
+
+ property QtObject objectProperty
+
+ property Component c: Component {
+ id: componentObject
+ QtObject {
+ }
+ }
+
+ function create() {
+ objectProperty = c.createObject(root);
+ }
+
+ function destroy() {
+ objectProperty.destroy();
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/dynamicDeletion.qml b/tests/auto/qml/qqmlecmascript/data/dynamicDeletion.qml
new file mode 100644
index 0000000000..f41e5262fd
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/dynamicDeletion.qml
@@ -0,0 +1,20 @@
+import Qt.test 1.0
+
+MyQmlObject{
+ id: obj
+ objectName: "obj"
+ function create()
+ {
+ obj.objectProperty = Qt.createQmlObject('import Qt.test 1.0; MyQmlObject{objectName:"emptyObject"}', obj);
+ }
+
+ function killOther()
+ {
+ obj.objectProperty.destroy(500);
+ }
+
+ function killMe()
+ {
+ obj.destroy();//Must not segfault
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/dynamicString.qml b/tests/auto/qml/qqmlecmascript/data/dynamicString.qml
new file mode 100644
index 0000000000..5693794c71
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/dynamicString.qml
@@ -0,0 +1,16 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+MyTypeObject {
+ stringProperty:"string:%0 false:%1 true:%2 uint32:%3 int32:%4 double:%5 date:%6!"
+ Component.onCompleted: {
+ var date = new Date();
+ date.setDate(11);
+ date.setMonth(1);
+ date.setFullYear(2011);
+ 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"));
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/elementAssign.qml b/tests/auto/qml/qqmlecmascript/data/elementAssign.qml
new file mode 100644
index 0000000000..0d75cbf6fc
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/elementAssign.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.0
+
+QtObject {
+ id: root
+
+ property bool test: bound.value == 1923
+
+ property ElementAssignType element: ElementAssignType { value: 1923 }
+ property ElementAssignType bound: root.element
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/enums.1.qml b/tests/auto/qml/qqmlecmascript/data/enums.1.qml
new file mode 100644
index 0000000000..6351823230
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/enums.1.qml
@@ -0,0 +1,20 @@
+import Qt.test 1.0
+import Qt.test 1.0 as Namespace
+
+MyQmlObject {
+ // Enums from non-namespaced type
+ property int a: MyQmlObject.EnumValue1
+ property int b: MyQmlObject.EnumValue2
+ property int c: MyQmlObject.EnumValue3
+ property int d: MyQmlObject.EnumValue4
+
+ // Enums from namespaced type
+ property int e: Namespace.MyQmlObject.EnumValue1
+ property int f: Namespace.MyQmlObject.EnumValue2
+ property int g: Namespace.MyQmlObject.EnumValue3
+ property int h: Namespace.MyQmlObject.EnumValue4
+
+ // Test that enums don't mask attached properties
+ property int i: MyQmlObject.value
+ property int j: Namespace.MyQmlObject.value
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/enums.2.qml b/tests/auto/qml/qqmlecmascript/data/enums.2.qml
new file mode 100644
index 0000000000..bdc672fadc
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/enums.2.qml
@@ -0,0 +1,8 @@
+import Qt.test 1.0
+import Qt.test 1.0 as Namespace
+
+MyQmlObject {
+ property int a: MyQmlObject.EnumValue10
+ property int b: Namespace.MyQmlObject.EnumValue10
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/eval.qml b/tests/auto/qml/qqmlecmascript/data/eval.qml
new file mode 100644
index 0000000000..a752b8c0d3
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/eval.qml
@@ -0,0 +1,27 @@
+import QtQuick 2.0
+
+QtObject {
+ property bool test1: false;
+ property bool test2: false;
+ property bool test3: false;
+ property bool test4: false;
+ property bool test5: false;
+
+
+ property int a: 7
+ property int b: 8
+
+ Component.onCompleted: {
+ var b = 9;
+
+ test1 = (eval("a") == 7);
+ test2 = (eval("b") == 9);
+ try {
+ eval("c");
+ } catch(e) {
+ test3 = true;
+ }
+ test4 = (eval("console") == console);
+ test5 = (eval("Qt") == Qt);
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/exception.js b/tests/auto/qml/qqmlecmascript/data/exception.js
new file mode 100644
index 0000000000..160bbfa5b6
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/exception.js
@@ -0,0 +1 @@
+throw("Whoops!");
diff --git a/tests/auto/qml/qqmlecmascript/data/exceptionClearsOnReeval.qml b/tests/auto/qml/qqmlecmascript/data/exceptionClearsOnReeval.qml
new file mode 100644
index 0000000000..a2f0d1a8b7
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/exceptionClearsOnReeval.qml
@@ -0,0 +1,6 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ property bool test: objectProperty.objectProperty.trueProperty
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/exceptionProducesWarning.qml b/tests/auto/qml/qqmlecmascript/data/exceptionProducesWarning.qml
new file mode 100644
index 0000000000..b8d5e5e60f
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/exceptionProducesWarning.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+MyQmlObject {
+ Component.onCompleted:
+ { throw(new Error("JS exception")) }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/exceptionProducesWarning2.qml b/tests/auto/qml/qqmlecmascript/data/exceptionProducesWarning2.qml
new file mode 100644
index 0000000000..a4ce55e245
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/exceptionProducesWarning2.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+MyQmlObject {
+ value: { throw(new Error("JS exception")) }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/extendedObjectPropertyLookup.qml b/tests/auto/qml/qqmlecmascript/data/extendedObjectPropertyLookup.qml
new file mode 100644
index 0000000000..2c382e871a
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/extendedObjectPropertyLookup.qml
@@ -0,0 +1,8 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+QtObject {
+ property MyExtendedObject a;
+ a: MyExtendedObject { id: root }
+ property int b: Math.max(root.extendedProperty, 0)
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/extendedObjectPropertyLookup2.qml b/tests/auto/qml/qqmlecmascript/data/extendedObjectPropertyLookup2.qml
new file mode 100644
index 0000000000..e4af3359d0
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/extendedObjectPropertyLookup2.qml
@@ -0,0 +1,14 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+QtObject {
+ id: root
+ property MyExtendedObject a;
+ a: MyExtendedObject {
+ id: obj
+ extendedProperty: 42;
+ }
+ function getValue() {
+ return obj.extendedProperty;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/extensionObjects.qml b/tests/auto/qml/qqmlecmascript/data/extensionObjects.qml
new file mode 100644
index 0000000000..7734a11dd8
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/extensionObjects.qml
@@ -0,0 +1,19 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+MyExtendedObject
+{
+ baseProperty: baseExtendedProperty
+ baseExtendedProperty: 13
+
+ coreProperty: extendedProperty
+ extendedProperty: 9
+
+ property QtObject nested: MyExtendedObject {
+ baseProperty: baseExtendedProperty
+ baseExtendedProperty: 13
+
+ coreProperty: extendedProperty
+ extendedProperty: 9
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/extensionObjectsPropertyOverride.qml b/tests/auto/qml/qqmlecmascript/data/extensionObjectsPropertyOverride.qml
new file mode 100644
index 0000000000..3c443cb975
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/extensionObjectsPropertyOverride.qml
@@ -0,0 +1,7 @@
+import Qt.test 1.0
+
+OverrideDefaultPropertyObject
+{
+ MyBaseExtendedObject {
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/forInLoop.qml b/tests/auto/qml/qqmlecmascript/data/forInLoop.qml
new file mode 100644
index 0000000000..f14367f177
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/forInLoop.qml
@@ -0,0 +1,13 @@
+import QtQuick 2.0
+
+QtObject {
+ property list<QtObject> objects
+ objects: [QtObject { objectName: "obj1" }, QtObject { objectName: "obj2" }, QtObject { objectName: "obj3" }]
+ property string listResult
+
+ function listProperty() {
+ for (var i in objects)
+ listResult += i + "=" + objects[i].objectName + "|"
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/function.qml b/tests/auto/qml/qqmlecmascript/data/function.qml
new file mode 100644
index 0000000000..af2da7023c
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/function.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.0
+
+QtObject {
+ property bool test1: false;
+ property bool test2: false;
+ property bool test3: false;
+
+ Component.onCompleted: {
+ var a = 10;
+
+ var func1 = new Function("a", "return a + 7");
+ var func2 = new Function("a", "return Qt.atob(a)");
+ var func3 = new Function("return a");
+
+ test1 = (func1(4) == 11);
+ test2 = (func2("Hello World!") == Qt.atob("Hello World!"));
+ try {
+ func3();
+ } catch(e) {
+ test3 = true;
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/functionAssignment.1.qml b/tests/auto/qml/qqmlecmascript/data/functionAssignment.1.qml
new file mode 100644
index 0000000000..09540f1f6e
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/functionAssignment.1.qml
@@ -0,0 +1,5 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ property variant a: function myFunction() { return 2; }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/functionAssignment.2.qml b/tests/auto/qml/qqmlecmascript/data/functionAssignment.2.qml
new file mode 100644
index 0000000000..0f78eaf1dc
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/functionAssignment.2.qml
@@ -0,0 +1,73 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+import "functionAssignment.js" as Script
+
+MyQmlObject {
+ property variant a
+ property int aNumber: 10
+
+ property bool assignToProperty: false
+ property bool assignToPropertyFromJsFile: false
+
+ property bool assignWithThis: false
+ property bool assignWithThisFromJsFile: false
+
+ property bool assignToValueType: false
+
+ property bool assignFuncWithoutReturn: false
+ property bool assignWrongType: false
+ property bool assignWrongTypeToValueType: false
+
+
+ onAssignToPropertyChanged: {
+ function myFunction() {
+ return aNumber * 10;
+ }
+ a = myFunction;
+ }
+
+ property QtObject obj: QtObject {
+ property int aNumber: 4212
+ function myFunction() {
+ return this.aNumber * 10; // should use the aNumber from root, not this object
+ }
+ }
+ onAssignWithThisChanged: {
+ a = obj.myFunction;
+ }
+
+ onAssignToPropertyFromJsFileChanged: {
+ Script.bindPropertyWithThis()
+ }
+
+ onAssignWithThisFromJsFileChanged: {
+ Script.bindProperty()
+ }
+
+ property Text text: Text { }
+ onAssignToValueTypeChanged: {
+ text.font.pixelSize = (function() { return aNumber * 10; })
+ a = (function() { return text.font.pixelSize; })
+ }
+
+
+ // detecting errors:
+
+ onAssignFuncWithoutReturnChanged: {
+ function myFunction() {
+ }
+ a = myFunction;
+ }
+
+ onAssignWrongTypeChanged: {
+ function myFunction() {
+ return 'a string';
+ }
+ aNumber = myFunction;
+ }
+
+ onAssignWrongTypeToValueTypeChanged: {
+ text.font.pixelSize = (function() { return 'a string'; })
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/functionAssignment.js b/tests/auto/qml/qqmlecmascript/data/functionAssignment.js
new file mode 100644
index 0000000000..14daa7629f
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/functionAssignment.js
@@ -0,0 +1,17 @@
+function bindProperty()
+{
+ a = (function(){ return aNumber * 10 })
+}
+
+
+function TestObject() { }
+TestObject.prototype.aNumber = 928349
+TestObject.prototype.bindFunction = function() {
+ return this.aNumber * 10 // this should not use the TestObject's aNumber
+}
+var testObj = new TestObject()
+
+function bindPropertyWithThis()
+{
+ a = testObj.bindFunction
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/functionErrors.qml b/tests/auto/qml/qqmlecmascript/data/functionErrors.qml
new file mode 100644
index 0000000000..230a626600
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/functionErrors.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.0
+
+QtObject {
+ function myFunction() {
+ a = 10;
+ }
+
+ Component.onCompleted: myFunction();
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/handleReferenceManagement.handle.1.qml b/tests/auto/qml/qqmlecmascript/data/handleReferenceManagement.handle.1.qml
new file mode 100644
index 0000000000..8a06c30d8c
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/handleReferenceManagement.handle.1.qml
@@ -0,0 +1,21 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ id: obj
+ objectName: "obj"
+ property CircularReferenceHandle first
+ property CircularReferenceHandle second
+
+ CircularReferenceHandle {
+ id: crh
+ objectName: "crh"
+ }
+
+ function createReference() {
+ first = crh.generate(crh);
+ second = crh.generate(crh);
+ // NOTE: manually add reference from first to second
+ // in unit test prior reparenting and gc.
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/handleReferenceManagement.handle.2.qml b/tests/auto/qml/qqmlecmascript/data/handleReferenceManagement.handle.2.qml
new file mode 100644
index 0000000000..91edc447e2
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/handleReferenceManagement.handle.2.qml
@@ -0,0 +1,22 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ id: obj
+ objectName: "obj"
+ property CircularReferenceHandle first
+ property CircularReferenceHandle second
+
+ CircularReferenceHandle {
+ id: crh
+ objectName: "crh"
+ }
+
+ function circularReference() {
+ // generate the circularly referential pair
+ first = crh.generate(crh);
+ second = crh.generate(crh);
+ // note: must manually reparent in unit test
+ // after setting the handle references.
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/handleReferenceManagement.object.1.qml b/tests/auto/qml/qqmlecmascript/data/handleReferenceManagement.object.1.qml
new file mode 100644
index 0000000000..70e8390677
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/handleReferenceManagement.object.1.qml
@@ -0,0 +1,27 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ id: obj
+ objectName: "obj"
+
+ property CircularReferenceObject first
+ property CircularReferenceObject second
+
+
+ CircularReferenceObject {
+ id: cro
+ objectName: "cro"
+ }
+
+ function createReference() {
+ // generate the objects
+ first = cro.generate(cro); // has parent, so won't be collected
+ second = cro.generate(); // no parent, but will be kept alive by first's reference
+ first.addReference(second);
+
+ // remove top level references
+ first = cro;
+ second = cro;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/handleReferenceManagement.object.2.qml b/tests/auto/qml/qqmlecmascript/data/handleReferenceManagement.object.2.qml
new file mode 100644
index 0000000000..2ddb9253eb
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/handleReferenceManagement.object.2.qml
@@ -0,0 +1,28 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ id: obj
+ objectName: "obj"
+
+ property CircularReferenceObject first
+ property CircularReferenceObject second
+
+
+ CircularReferenceObject {
+ id: cro
+ objectName: "cro"
+ }
+
+ function circularReference() {
+ // generate the circularly referential pair - they should still be collected
+ first = cro.generate(); // no parent, so should be collected
+ second = cro.generate(); // no parent, so should be collected
+ first.addReference(second);
+ second.addReference(first);
+
+ // remove top level references
+ first = cro;
+ second = cro;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/idShortcutInvalidates.1.qml b/tests/auto/qml/qqmlecmascript/data/idShortcutInvalidates.1.qml
new file mode 100644
index 0000000000..ece23269f1
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/idShortcutInvalidates.1.qml
@@ -0,0 +1,13 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+MyQmlObject {
+ objectProperty: if(1) otherObject
+
+ property variant obj
+
+ obj: QtObject {
+ id: otherObject
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/idShortcutInvalidates.qml b/tests/auto/qml/qqmlecmascript/data/idShortcutInvalidates.qml
new file mode 100644
index 0000000000..650ed7c73e
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/idShortcutInvalidates.qml
@@ -0,0 +1,12 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+MyQmlObject {
+ objectProperty: otherObject
+
+ property variant obj
+
+ obj: QtObject {
+ id: otherObject
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/importScope.1.js b/tests/auto/qml/qqmlecmascript/data/importScope.1.js
new file mode 100644
index 0000000000..4c556f9e96
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/importScope.1.js
@@ -0,0 +1 @@
+var value = 240
diff --git a/tests/auto/qml/qqmlecmascript/data/importScope.2.js b/tests/auto/qml/qqmlecmascript/data/importScope.2.js
new file mode 100644
index 0000000000..291fb9d2cc
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/importScope.2.js
@@ -0,0 +1,3 @@
+function getValue() {
+ return ImportScope1.value
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/importScope.qml b/tests/auto/qml/qqmlecmascript/data/importScope.qml
new file mode 100644
index 0000000000..9b907f11f9
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/importScope.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+import "importScope.1.js" as ImportScope1
+import "importScope.2.js" as ImportScope2
+
+QtObject {
+ property int test: ImportScope2.getValue()
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/in.qml b/tests/auto/qml/qqmlecmascript/data/in.qml
new file mode 100644
index 0000000000..f84c9a1481
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/in.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+ property bool test1: "x" in root
+ property bool test2: !("foo" in root)
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/include.js b/tests/auto/qml/qqmlecmascript/data/include.js
new file mode 100644
index 0000000000..232fd808f8
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/include.js
@@ -0,0 +1,8 @@
+var test1 = true
+var test2 = false
+var test3 = false
+
+function go() {
+ Qt.include("js/include2.js");
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/include.qml b/tests/auto/qml/qqmlecmascript/data/include.qml
new file mode 100644
index 0000000000..5ce2ed78ec
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/include.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.0
+import "include.js" as IncludeTest
+
+QtObject {
+ property int test0: 0
+ property bool test1: false
+ property bool test2: false
+ property bool test2_1: false
+ property bool test3: false
+ property bool test3_1: false
+
+ property int testValue: 99
+
+ Component.onCompleted: {
+ IncludeTest.go();
+ test0 = IncludeTest.value
+ test1 = IncludeTest.test1
+ test2 = IncludeTest.test2
+ test2_1 = IncludeTest.test2_1
+ test3 = IncludeTest.test3
+ test3_1 = IncludeTest.test3_1
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/include_callback.js b/tests/auto/qml/qqmlecmascript/data/include_callback.js
new file mode 100644
index 0000000000..ea19eba300
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/include_callback.js
@@ -0,0 +1,11 @@
+function go() {
+ var a = Qt.include("missing.js", function(o) { test2 = o.status == o.NETWORK_ERROR });
+ test1 = a.status == a.NETWORK_ERROR
+
+ var b = Qt.include("blank.js", function(o) { test4 = o.status == o.OK });
+ test3 = b.status == b.OK
+
+ var c = Qt.include("exception.js", function(o) { test6 = o.status == o.EXCEPTION });
+ test5 = c.status == c.EXCEPTION
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/include_callback.qml b/tests/auto/qml/qqmlecmascript/data/include_callback.qml
new file mode 100644
index 0000000000..fbebcdcd58
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/include_callback.qml
@@ -0,0 +1,15 @@
+import QtQuick 2.0
+import "include_callback.js" as IncludeTest
+
+QtObject {
+ property bool test1: false
+ property bool test2: false
+ property bool test3: false
+ property bool test4: false
+ property bool test5: false
+ property bool test6: false
+
+ Component.onCompleted: {
+ IncludeTest.go();
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/include_pragma.qml b/tests/auto/qml/qqmlecmascript/data/include_pragma.qml
new file mode 100644
index 0000000000..7b23c76baa
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/include_pragma.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.0
+import "include_pragma_outer.js" as Script
+
+Item {
+ property int test1
+
+ Component.onCompleted: {
+ test1 = Script.callFunction()
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/include_pragma_inner.js b/tests/auto/qml/qqmlecmascript/data/include_pragma_inner.js
new file mode 100644
index 0000000000..a0380a25df
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/include_pragma_inner.js
@@ -0,0 +1,5 @@
+.pragma library
+
+function getValue() {
+ return 100;
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/include_pragma_outer.js b/tests/auto/qml/qqmlecmascript/data/include_pragma_outer.js
new file mode 100644
index 0000000000..d87bafc816
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/include_pragma_outer.js
@@ -0,0 +1,6 @@
+Qt.include("include_pragma_inner.js")
+
+function callFunction() {
+ return getValue();
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/include_remote.js b/tests/auto/qml/qqmlecmascript/data/include_remote.js
new file mode 100644
index 0000000000..e6a4676819
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/include_remote.js
@@ -0,0 +1,26 @@
+var myvar = 10;
+
+function go()
+{
+ var a = Qt.include("http://127.0.0.1:8111/remote_file.js",
+ function(o) {
+ test2 = o.status == o.OK
+ test3 = a.status == a.OK
+ test4 = myvar == 13
+
+ done = true;
+ });
+ test1 = a.status == a.LOADING
+
+
+ var b = Qt.include("http://127.0.0.1:8111/exception.js",
+ function(o) {
+ test7 = o.status == o.EXCEPTION
+ test8 = b.status == a.EXCEPTION
+ test9 = b.exception.toString() == "Whoops!";
+ test10 = o.exception.toString() == "Whoops!";
+
+ done2 = true;
+ });
+ test6 = b.status == b.LOADING
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/include_remote.qml b/tests/auto/qml/qqmlecmascript/data/include_remote.qml
new file mode 100644
index 0000000000..fe020a55df
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/include_remote.qml
@@ -0,0 +1,21 @@
+import QtQuick 2.0
+import "include_remote.js" as IncludeTest
+
+QtObject {
+ property bool done: false
+ property bool done2: false
+
+ property bool test1: false
+ property bool test2: false
+ property bool test3: false
+ property bool test4: false
+ property bool test5: false
+
+ property bool test6: false
+ property bool test7: false
+ property bool test8: false
+ property bool test9: false
+ property bool test10: false
+
+ Component.onCompleted: IncludeTest.go();
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/include_remote_missing.js b/tests/auto/qml/qqmlecmascript/data/include_remote_missing.js
new file mode 100644
index 0000000000..cc90860cc9
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/include_remote_missing.js
@@ -0,0 +1,13 @@
+function go()
+{
+ var a = Qt.include("http://127.0.0.1:8111/missing.js",
+ function(o) {
+ test2 = o.status == o.NETWORK_ERROR
+ test3 = a.status == a.NETWORK_ERROR
+
+ done = true;
+ });
+
+ test1 = a.status == a.LOADING
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/include_remote_missing.qml b/tests/auto/qml/qqmlecmascript/data/include_remote_missing.qml
new file mode 100644
index 0000000000..e8ef609fed
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/include_remote_missing.qml
@@ -0,0 +1,12 @@
+import QtQuick 2.0
+import "include_remote_missing.js" as IncludeTest
+
+QtObject {
+ property bool done: false
+
+ property bool test1: false
+ property bool test2: false
+ property bool test3: false
+
+ Component.onCompleted: IncludeTest.go();
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/include_shared.js b/tests/auto/qml/qqmlecmascript/data/include_shared.js
new file mode 100644
index 0000000000..a49c07bbfc
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/include_shared.js
@@ -0,0 +1,12 @@
+.pragma library
+
+var test1 = true
+var test2 = false
+var test3 = false
+
+var testValue = 99;
+
+function go() {
+ Qt.include("js/include2.js");
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/include_shared.qml b/tests/auto/qml/qqmlecmascript/data/include_shared.qml
new file mode 100644
index 0000000000..28b1003fd4
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/include_shared.qml
@@ -0,0 +1,22 @@
+import QtQuick 2.0
+import "include_shared.js" as IncludeTest
+
+QtObject {
+ property int test0: 0
+ property bool test1: false
+ property bool test2: false
+ property bool test2_1: false
+ property bool test3: false
+ property bool test3_1: false
+
+ Component.onCompleted: {
+ IncludeTest.go();
+ test0 = IncludeTest.value
+ test1 = IncludeTest.test1
+ test2 = IncludeTest.test2
+ test2_1 = IncludeTest.test2_1
+ test3 = IncludeTest.test3
+ test3_1 = IncludeTest.test3_1
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/invokableObjectArg.qml b/tests/auto/qml/qqmlecmascript/data/invokableObjectArg.qml
new file mode 100644
index 0000000000..160a90b574
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/invokableObjectArg.qml
@@ -0,0 +1,9 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+MyQmlObject {
+ id: root
+ Component.onCompleted: {
+ root.myinvokable(root);
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/invokableObjectRet.qml b/tests/auto/qml/qqmlecmascript/data/invokableObjectRet.qml
new file mode 100644
index 0000000000..4612273727
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/invokableObjectRet.qml
@@ -0,0 +1,11 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+MyQmlObject {
+ id: root
+ property bool test: false
+ Component.onCompleted: {
+ test = (root.returnme() == root)
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/js/include2.js b/tests/auto/qml/qqmlecmascript/data/js/include2.js
new file mode 100644
index 0000000000..2a0c039dfa
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/js/include2.js
@@ -0,0 +1,4 @@
+test2 = true
+var test2_1 = true
+
+Qt.include("include3.js");
diff --git a/tests/auto/qml/qqmlecmascript/data/js/include3.js b/tests/auto/qml/qqmlecmascript/data/js/include3.js
new file mode 100644
index 0000000000..84b2770b6f
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/js/include3.js
@@ -0,0 +1,3 @@
+test3 = true
+var test3_1 = true
+var value = testValue
diff --git a/tests/auto/qml/qqmlecmascript/data/jsObject.qml b/tests/auto/qml/qqmlecmascript/data/jsObject.qml
new file mode 100644
index 0000000000..4223c25f31
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsObject.qml
@@ -0,0 +1,12 @@
+import QtQuick 2.0
+
+QtObject {
+ property int test
+
+ Component.onCompleted: {
+ var o = new Object;
+ o.test = 92;
+ test = o.test;
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/SpecialRectangleOne.qml b/tests/auto/qml/qqmlecmascript/data/jsimport/SpecialRectangleOne.qml
new file mode 100644
index 0000000000..97c72bd9a6
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/SpecialRectangleOne.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+
+import "importPragmaLibrary.js" as TestPragmaLibraryImport
+
+Rectangle {
+ width: TestPragmaLibraryImport.importIncrementedValue()
+ height: width + 15
+ color: "red"
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/SpecialRectangleTwo.qml b/tests/auto/qml/qqmlecmascript/data/jsimport/SpecialRectangleTwo.qml
new file mode 100644
index 0000000000..d006343782
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/SpecialRectangleTwo.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+
+import "importPragmaLibrary.js" as TestPragmaLibraryImport
+
+Rectangle {
+ width: TestPragmaLibraryImport.importIncrementedValue()
+ height: width + 5
+ color: "blue"
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/importFive.js b/tests/auto/qml/qqmlecmascript/data/jsimport/importFive.js
new file mode 100644
index 0000000000..e458094552
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/importFive.js
@@ -0,0 +1,3 @@
+function importFiveFunction() {
+ return '5';
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/importFour.js b/tests/auto/qml/qqmlecmascript/data/jsimport/importFour.js
new file mode 100644
index 0000000000..faddc15c9d
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/importFour.js
@@ -0,0 +1,9 @@
+.pragma library
+
+function importFourFunction() {
+ return '4';
+}
+
+function greetingString() {
+ return 'Hello, World!';
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/importModuleApi.js b/tests/auto/qml/qqmlecmascript/data/jsimport/importModuleApi.js
new file mode 100644
index 0000000000..7a4f434665
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/importModuleApi.js
@@ -0,0 +1,5 @@
+.import Qt.test 1.0 as QObjectModuleApi
+
+function testFunc() {
+ return QObjectModuleApi.qobjectTestProperty
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/importOne.js b/tests/auto/qml/qqmlecmascript/data/jsimport/importOne.js
new file mode 100644
index 0000000000..338c4e042f
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/importOne.js
@@ -0,0 +1,13 @@
+.import "importTwo.js" as ImportTwoJs
+.import "importThree.js" as ImportThreeJs
+
+function greetingString() {
+ if (ImportTwoJs.greetingString().length > 0) {
+ return ImportTwoJs.greetingString();
+ }
+ return ImportThreeJs.greetingString();
+}
+
+function importOneFunction() {
+ return '1';
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/importPragmaLibrary.js b/tests/auto/qml/qqmlecmascript/data/jsimport/importPragmaLibrary.js
new file mode 100644
index 0000000000..c746fef14b
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/importPragmaLibrary.js
@@ -0,0 +1,9 @@
+.pragma library
+
+var i = 4;
+
+// .pragma library, so should be callable from multiple .qml with shared i.
+function importIncrementedValue() {
+ i = i + 1;
+ return i;
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/importPragmaLibraryWithImports.js b/tests/auto/qml/qqmlecmascript/data/jsimport/importPragmaLibraryWithImports.js
new file mode 100644
index 0000000000..3f2e6589dd
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/importPragmaLibraryWithImports.js
@@ -0,0 +1,9 @@
+.pragma library
+.import "importFive.js" as ImportFive
+
+var i = 4;
+
+function importIncrementedValue() {
+ i = i + 1;
+ return (i + ImportFive.importFiveFunction()); // i + '5' (not i+5)
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/importPragmaLibraryWithPragmaLibraryImports.js b/tests/auto/qml/qqmlecmascript/data/jsimport/importPragmaLibraryWithPragmaLibraryImports.js
new file mode 100644
index 0000000000..fa6497d99b
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/importPragmaLibraryWithPragmaLibraryImports.js
@@ -0,0 +1,11 @@
+.pragma library
+.import "importPragmaLibrary.js" as LibraryImport
+
+var i = 10;
+
+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());
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/importThree.js b/tests/auto/qml/qqmlecmascript/data/jsimport/importThree.js
new file mode 100644
index 0000000000..3917134ee2
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/importThree.js
@@ -0,0 +1,9 @@
+.import "importFour.js" as ImportFourJs
+
+function greetingString() {
+ return ImportFourJs.greetingString();
+}
+
+function importThreeFunction() {
+ return '3';
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/importTwo.js b/tests/auto/qml/qqmlecmascript/data/jsimport/importTwo.js
new file mode 100644
index 0000000000..45b3c9a74d
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/importTwo.js
@@ -0,0 +1,10 @@
+.import "importFour.js" as ImportFourJs
+.import "importFive.js" as ImportFiveJs
+
+function greetingString() {
+ return ImportFourJs.greetingString();
+}
+
+function importTwoFunction() {
+ return '2';
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/importWithNoImports.js b/tests/auto/qml/qqmlecmascript/data/jsimport/importWithNoImports.js
new file mode 100644
index 0000000000..83426c425c
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/importWithNoImports.js
@@ -0,0 +1,11 @@
+// This js file has no imports, and so should inherit
+// scope from the QML file which includes it.
+
+function componentError() {
+ var i = 5;
+ var errorIsOne = Component.error == 1;
+ if (errorIsOne == true) {
+ i = i + 7;
+ }
+ return i;
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/testImport.qml b/tests/auto/qml/qqmlecmascript/data/jsimport/testImport.qml
new file mode 100644
index 0000000000..456a10c7f0
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/testImport.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+
+import "testScriptImport.js" as TestScriptImport
+import "testModuleImport.js" as TestModuleImport
+
+QtObject {
+ id: testQtObject
+
+ property string importedScriptStringValue: TestScriptImport.greetingText
+ property int importedScriptFunctionValue: TestScriptImport.randomInteger(1, 20)
+
+ property int importedModuleAttachedPropertyValue: TestModuleImport.importedAttachedPropertyValue(testQtObject)
+ property int importedModuleEnumValue: TestModuleImport.importedEnumValue
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/testImportModuleApi.qml b/tests/auto/qml/qqmlecmascript/data/jsimport/testImportModuleApi.qml
new file mode 100644
index 0000000000..b3e545dd7c
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/testImportModuleApi.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.0
+import "importModuleApi.js" as Script
+
+Item {
+ property variant testValue: 5
+
+ Component.onCompleted: {
+ testValue = Script.testFunc();
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/testImportPragmaLibrary.qml b/tests/auto/qml/qqmlecmascript/data/jsimport/testImportPragmaLibrary.qml
new file mode 100644
index 0000000000..29de15c197
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/testImportPragmaLibrary.qml
@@ -0,0 +1,20 @@
+import QtQuick 2.0
+
+// We use the components specified in SpecialRectangleOne.qml and SpecialRectangleTwo.qml
+
+QtObject {
+ id: testQtObject
+
+ property SpecialRectangleOne a;
+ property SpecialRectangleTwo b;
+
+ a: SpecialRectangleOne {
+ id: rectangleOne
+ }
+ b: SpecialRectangleTwo {
+ id: rectangleTwo
+ }
+
+ // this should be: (5 + 15) + (6 + 5) == 31
+ property int testValue: rectangleOne.height + rectangleTwo.height
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/testImportPragmaLibraryWithImports.qml b/tests/auto/qml/qqmlecmascript/data/jsimport/testImportPragmaLibraryWithImports.qml
new file mode 100644
index 0000000000..6a7459d3bb
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/testImportPragmaLibraryWithImports.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+import "importPragmaLibraryWithImports.js" as LibraryImport
+
+QtObject {
+ id: root
+ property int testValue: LibraryImport.importIncrementedValue(); // valueOf(4 + 1 + '5') = valueOf('55') = 55
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml b/tests/auto/qml/qqmlecmascript/data/jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml
new file mode 100644
index 0000000000..01f08dbdc3
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+import "importPragmaLibraryWithPragmaLibraryImports.js" as LibraryImport
+
+QtObject {
+ id: root
+ property int testValue: LibraryImport.importIncrementedValue(); // 10 + 1 + (7 due to previous tests) = 18
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/testImportScoping.qml b/tests/auto/qml/qqmlecmascript/data/jsimport/testImportScoping.qml
new file mode 100644
index 0000000000..aff61cc436
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/testImportScoping.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.0
+
+// For backward compatibility, importing a script which has no imports,
+// should run the script in the parent context. See QTBUG-17518.
+
+import "importWithNoImports.js" as TestNoImportScoping
+
+QtObject {
+ id: testQtObject
+ property int componentError: TestNoImportScoping.componentError()
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/testModuleImport.js b/tests/auto/qml/qqmlecmascript/data/jsimport/testModuleImport.js
new file mode 100644
index 0000000000..69bc1c9887
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/testModuleImport.js
@@ -0,0 +1,8 @@
+.import Qt.test 1.0 as JsQtTest // test that we can import elements from .js files
+
+function importedAttachedPropertyValue(obj) {
+ return obj.JsQtTest.MyQmlObject.value; // attached property, value = 19.
+}
+
+var importedEnumValue = JsQtTest.MyQmlObject.EnumValue3 // the actual value of this enum value is "2"
+
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimport/testScriptImport.js b/tests/auto/qml/qqmlecmascript/data/jsimport/testScriptImport.js
new file mode 100644
index 0000000000..2ecccd8816
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsimport/testScriptImport.js
@@ -0,0 +1,11 @@
+.import "importOne.js" as ImportOneJs // test that we can import scripts from .js files
+
+var greetingText = ImportOneJs.greetingString()
+
+function randomInteger(min, max) {
+ if (max > min) {
+ if (min > 10) return min;
+ return max;
+ }
+ return min;
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimportfail/failFive.qml b/tests/auto/qml/qqmlecmascript/data/jsimportfail/failFive.qml
new file mode 100644
index 0000000000..73193a35a5
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsimportfail/failFive.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.0
+
+// This should fail, since if the script does have imports
+// of its own, it should run in its own context.
+
+import "importWithImports.js" as TestImportScoping
+
+QtObject {
+ id: testQtObject
+ property int componentError: TestImportScoping.componentError()
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimportfail/failFour.qml b/tests/auto/qml/qqmlecmascript/data/jsimportfail/failFour.qml
new file mode 100644
index 0000000000..ef2fc591b3
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsimportfail/failFour.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+import "testModuleImport.js" as TestModuleImport
+
+QtObject {
+ property int importedModuleEnumValue: JsQtTest.MyQmlObject.EnumValue3 // should fail - the typenames available in TestModuleImport should not be available in this scope
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimportfail/failOne.qml b/tests/auto/qml/qqmlecmascript/data/jsimportfail/failOne.qml
new file mode 100644
index 0000000000..d0c37ad9ba
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsimportfail/failOne.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+import "testScriptImport.js" as TestScriptImport
+
+QtObject {
+ property string importScriptFunctionValue: TestScriptImport.ImportOneJs.greetingString() // should fail - the context of TestScriptImport is private to TestScriptImport.
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimportfail/failThree.qml b/tests/auto/qml/qqmlecmascript/data/jsimportfail/failThree.qml
new file mode 100644
index 0000000000..edd103bd82
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsimportfail/failThree.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+
+import "testModuleImport.js" as TestModuleImport
+
+QtObject {
+ id: testQtObject
+ property int importedModuleAttachedPropertyValue: testQtObject.TestModuleImport.JsQtTest.MyQmlObject.value // should fail - the context of TestScriptImport is private to TestScriptImport.
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimportfail/failTwo.qml b/tests/auto/qml/qqmlecmascript/data/jsimportfail/failTwo.qml
new file mode 100644
index 0000000000..28e2026f8d
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsimportfail/failTwo.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+import "testScriptImport.js" as TestScriptImport
+
+QtObject {
+ property string importScriptFunctionValue: ImportOneJs.greetingString() // should fail - the typenames in TestScriptImport should not be visible from this scope
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimportfail/importOne.js b/tests/auto/qml/qqmlecmascript/data/jsimportfail/importOne.js
new file mode 100644
index 0000000000..45fd9c75dd
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsimportfail/importOne.js
@@ -0,0 +1,7 @@
+function greetingString() {
+ return 'Hello, World!';
+}
+
+function importOneFunction() {
+ return '1';
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimportfail/importPragmaLibrary.js b/tests/auto/qml/qqmlecmascript/data/jsimportfail/importPragmaLibrary.js
new file mode 100644
index 0000000000..ad0e6946a2
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsimportfail/importPragmaLibrary.js
@@ -0,0 +1,11 @@
+.pragma library
+
+// .pragma library, so shouldn't inherit imports from any .qml file.
+function importValue() {
+ var i = 3;
+ var errorIsOne = Component.error == 1; // this line should fail.
+ if (errorIsOne == true) {
+ i = i + 4;
+ }
+ return i;
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimportfail/importWithImports.js b/tests/auto/qml/qqmlecmascript/data/jsimportfail/importWithImports.js
new file mode 100644
index 0000000000..6d77ceccb1
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsimportfail/importWithImports.js
@@ -0,0 +1,13 @@
+.import "importOne.js" as ImportOne
+
+// This js file has imports, so should not inherit
+// scope from the QML file which includes it.
+
+function componentError() {
+ var i = 3;
+ var errorIsOne = Component.error == 1; // this line should fail.
+ if (errorIsOne == true) {
+ i = i + 4;
+ }
+ return i;
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimportfail/testImportPragmaLibrary.qml b/tests/auto/qml/qqmlecmascript/data/jsimportfail/testImportPragmaLibrary.qml
new file mode 100644
index 0000000000..f04ce007d8
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsimportfail/testImportPragmaLibrary.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+
+import "importPragmaLibrary.js" as ImportPragmaLibrary
+
+QtObject {
+ id: testQtObject
+ property int testValue: ImportPragmaLibrary.importValue()
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimportfail/testModuleImport.js b/tests/auto/qml/qqmlecmascript/data/jsimportfail/testModuleImport.js
new file mode 100644
index 0000000000..69bc1c9887
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsimportfail/testModuleImport.js
@@ -0,0 +1,8 @@
+.import Qt.test 1.0 as JsQtTest // test that we can import elements from .js files
+
+function importedAttachedPropertyValue(obj) {
+ return obj.JsQtTest.MyQmlObject.value; // attached property, value = 19.
+}
+
+var importedEnumValue = JsQtTest.MyQmlObject.EnumValue3 // the actual value of this enum value is "2"
+
diff --git a/tests/auto/qml/qqmlecmascript/data/jsimportfail/testScriptImport.js b/tests/auto/qml/qqmlecmascript/data/jsimportfail/testScriptImport.js
new file mode 100644
index 0000000000..2ecccd8816
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/jsimportfail/testScriptImport.js
@@ -0,0 +1,11 @@
+.import "importOne.js" as ImportOneJs // test that we can import scripts from .js files
+
+var greetingText = ImportOneJs.greetingString()
+
+function randomInteger(min, max) {
+ if (max > min) {
+ if (min > 10) return min;
+ return max;
+ }
+ return min;
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/libraryScriptAssert.js b/tests/auto/qml/qqmlecmascript/data/libraryScriptAssert.js
new file mode 100644
index 0000000000..3ffdb339ad
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/libraryScriptAssert.js
@@ -0,0 +1,6 @@
+.pragma library
+
+function test(target)
+{
+ var a = target.a;
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/libraryScriptAssert.qml b/tests/auto/qml/qqmlecmascript/data/libraryScriptAssert.qml
new file mode 100644
index 0000000000..5884e2719b
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/libraryScriptAssert.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+import "libraryScriptAssert.js" as Test
+
+QtObject {
+ id: root
+ Component.onCompleted: Test.test(root);
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/listAssignment.qml b/tests/auto/qml/qqmlecmascript/data/listAssignment.qml
new file mode 100644
index 0000000000..6e6039715b
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/listAssignment.qml
@@ -0,0 +1,20 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ id: root
+ width: 640
+ height: 480
+
+ property int list1length: list1.length
+
+ property list<MyQmlObject> list1
+ property list<MyQmlObject> list2: [
+ MyQmlObject { id: one; value: 100 },
+ MyQmlObject { id: two; value: 300 }
+ ]
+
+ Component.onCompleted: {
+ root.list1 = root.list2;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/listProperties.qml b/tests/auto/qml/qqmlecmascript/data/listProperties.qml
new file mode 100644
index 0000000000..bdb1265a21
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/listProperties.qml
@@ -0,0 +1,24 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+MyQmlObject {
+ id: root
+
+ objectListProperty: [
+ QtObject { property int a: 10 },
+ QtObject { property int a: 11 }
+ ]
+
+ function calcTest1() {
+ var rv = 0;
+ for (var ii = 0; ii < root.objectListProperty.length; ++ii) {
+ rv += root.objectListProperty[ii].a;
+ }
+ return rv;
+ }
+
+ property int test1: calcTest1();
+ property int test2: root.objectListProperty.length
+ property bool test3: root.objectListProperty[1] != undefined
+ property bool test4: root.objectListProperty[100] == undefined
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/listToVariant.qml b/tests/auto/qml/qqmlecmascript/data/listToVariant.qml
new file mode 100644
index 0000000000..690024b928
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/listToVariant.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+QtObject {
+ property variant test: children
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/metaobjectRevision.qml b/tests/auto/qml/qqmlecmascript/data/metaobjectRevision.qml
new file mode 100644
index 0000000000..77accd80de
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/metaobjectRevision.qml
@@ -0,0 +1,7 @@
+import Qt.test 1.1
+
+MyRevisionedClass
+{
+ prop1: prop2
+ onSignal1: method2()
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/metaobjectRevision2.qml b/tests/auto/qml/qqmlecmascript/data/metaobjectRevision2.qml
new file mode 100644
index 0000000000..36057cb902
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/metaobjectRevision2.qml
@@ -0,0 +1,9 @@
+import Qt.test 1.1
+
+MyRevisionedSubclass
+{
+ prop1: prop3
+ onSignal1: method2()
+ prop3: prop4
+ onSignal3: method4()
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/metaobjectRevision3.qml b/tests/auto/qml/qqmlecmascript/data/metaobjectRevision3.qml
new file mode 100644
index 0000000000..81769e98f7
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/metaobjectRevision3.qml
@@ -0,0 +1,8 @@
+import Qt.test 1.0
+
+MyRevisionedSubclass
+{
+ prop1: prop3
+ onSignal1: method1()
+ onSignal3: method3()
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/metaobjectRevision4.qml b/tests/auto/qml/qqmlecmascript/data/metaobjectRevision4.qml
new file mode 100644
index 0000000000..6ebe4790bb
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/metaobjectRevision4.qml
@@ -0,0 +1,14 @@
+import Qt.test 1.1
+import QtQuick 2.0
+
+QtObject {
+ property variant a
+ property real test
+
+ a: MyRevisionedClass {
+ prop2: 11
+
+ Component.onCompleted: test = prop2
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/metaobjectRevisionErrors.qml b/tests/auto/qml/qqmlecmascript/data/metaobjectRevisionErrors.qml
new file mode 100644
index 0000000000..8a7e24d788
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/metaobjectRevisionErrors.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+MyRevisionedClass
+{
+ // Will not hit optimizer
+ property real p1: prop1 % 3
+ property real p2: prop2 % 3
+
+ // Should hit optimizer
+ property real p3: prop2
+
+ Component.onCompleted: method2()
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/metaobjectRevisionErrors2.qml b/tests/auto/qml/qqmlecmascript/data/metaobjectRevisionErrors2.qml
new file mode 100644
index 0000000000..43e87948cd
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/metaobjectRevisionErrors2.qml
@@ -0,0 +1,24 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+MyRevisionedSubclass
+{
+ // Will not hit optimizer
+ property real p1: prop1 % 3
+ property real p2: prop2 % 3
+ property real p3: prop3 % 3
+ property real p4: prop4 % 3
+
+ // Should hit optimizer
+ property real p5: prop1
+ property real p6: prop2
+ property real p7: prop3
+ property real p8: prop4
+
+ Component.onCompleted: {
+ method1()
+ method2()
+ method3()
+ method4()
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/metaobjectRevisionErrors3.qml b/tests/auto/qml/qqmlecmascript/data/metaobjectRevisionErrors3.qml
new file mode 100644
index 0000000000..2f82d685fa
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/metaobjectRevisionErrors3.qml
@@ -0,0 +1,36 @@
+import QtQuick 2.0
+import Qt.test 1.1
+
+MyRevisionedSubclass
+{
+ // Will not hit optimizer
+ property real pA: propA % 3
+ property real pB: propB % 3
+ property real pC: propC % 3
+ property real pD: propD % 3
+ property real p1: prop1 % 3
+ property real p2: prop2 % 3
+ property real p3: prop3 % 3
+ property real p4: prop4 % 3
+
+ // Should hit optimizer
+ property real pE: propA
+ property real pF: propB
+ property real pG: propC
+ property real pH: propD
+ property real p5: prop1
+ property real p6: prop2
+ property real p7: prop3
+ property real p8: prop4
+
+ Component.onCompleted: {
+ methodA()
+ methodB()
+ methodC()
+ methodD()
+ method1()
+ method2()
+ method3()
+ method4()
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/methods.1.qml b/tests/auto/qml/qqmlecmascript/data/methods.1.qml
new file mode 100644
index 0000000000..0bbee16df8
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/methods.1.qml
@@ -0,0 +1,6 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ id: myObject
+ onBasicSignal: myObject.methodNoArgs()
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/methods.2.qml b/tests/auto/qml/qqmlecmascript/data/methods.2.qml
new file mode 100644
index 0000000000..9f0c6b15fe
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/methods.2.qml
@@ -0,0 +1,6 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ id: myObject
+ onBasicSignal: myObject.method(163)
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/methods.3.qml b/tests/auto/qml/qqmlecmascript/data/methods.3.qml
new file mode 100644
index 0000000000..365780a560
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/methods.3.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+QtObject {
+ function testFunction() { return 19; }
+
+ property int test: testFunction()
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/methods.4.qml b/tests/auto/qml/qqmlecmascript/data/methods.4.qml
new file mode 100644
index 0000000000..a3bd7bebf8
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/methods.4.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.0
+
+MethodsObject {
+ function testFunction2() { return 17; }
+ function testFunction3() { return 16; }
+
+ property int test: testFunction()
+ property int test2: testFunction2()
+ property int test3: testFunction3()
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/methods.5.qml b/tests/auto/qml/qqmlecmascript/data/methods.5.qml
new file mode 100644
index 0000000000..ede2759e2e
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/methods.5.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+
+Item {
+ property alias blah: item.x
+ Item { id: item }
+
+ function testFunction() { return 9; }
+ property int test: testFunction();
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/moduleapi/moduleApiMajorVersionFail.qml b/tests/auto/qml/qqmlecmascript/data/moduleapi/moduleApiMajorVersionFail.qml
new file mode 100644
index 0000000000..fb050f65bc
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/moduleapi/moduleApiMajorVersionFail.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.0
+
+// this qml file attempts to import an invalid version of a qobject module API.
+
+import Qt.test.qobjectApi 4.0 as QtTestMajorVersionQObjectApi // qobject module API installed into existing uri with nonexistent major version
+
+QtObject {
+ property int qobjectMajorVersionTest: QtTestMajorVersionQObjectApi.qobjectTestProperty
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/moduleapi/moduleApiMinorVersionFail.qml b/tests/auto/qml/qqmlecmascript/data/moduleapi/moduleApiMinorVersionFail.qml
new file mode 100644
index 0000000000..e06be667f7
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/moduleapi/moduleApiMinorVersionFail.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.0
+
+// this qml file attempts to import an invalid version of a qobject module API.
+
+import Qt.test.qobjectApi 1.2 as QtTestMinorVersionQObjectApi // qobject module API installed into existing uri with nonexistent minor version
+
+QtObject {
+ property int qobjectMinorVersionTest: QtTestMinorVersionedQObjectApi.qobjectTestProperty
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/moduleapi/qobjectModuleApi.qml b/tests/auto/qml/qqmlecmascript/data/moduleapi/qobjectModuleApi.qml
new file mode 100644
index 0000000000..718a64652d
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/moduleapi/qobjectModuleApi.qml
@@ -0,0 +1,21 @@
+import QtQuick 2.0
+
+import Qt.test 1.0 as QtTest // module API installed into existing uri
+import Qt.test.qobjectApi 1.0 as QtTestQObjectApi // qobject module API installed into new uri
+import Qt.test.qobjectApi 1.3 as QtTestMinorVersionQObjectApi // qobject module API installed into existing uri with new minor version
+import Qt.test.qobjectApi 2.0 as QtTestMajorVersionQObjectApi // qobject module API installed into existing uri with new major version
+import Qt.test.qobjectApiParented 1.0 as QtTestParentedQObjectApi // qobject (with parent) module API installed into a new uri
+
+QtObject {
+ property int existingUriTest: QtTest.qobjectTestProperty
+ property int qobjectTest: QtTestQObjectApi.qobjectTestProperty
+ property int qobjectMethodTest: 2
+ property int qobjectMinorVersionTest: QtTestMinorVersionQObjectApi.qobjectTestProperty
+ property int qobjectMajorVersionTest: QtTestMajorVersionQObjectApi.qobjectTestProperty
+ property int qobjectParentedTest: QtTestParentedQObjectApi.qobjectTestProperty
+
+ Component.onCompleted: {
+ qobjectMethodTest = QtTestQObjectApi.qobjectTestMethod();
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/moduleapi/qobjectModuleApiCaching.qml b/tests/auto/qml/qqmlecmascript/data/moduleapi/qobjectModuleApiCaching.qml
new file mode 100644
index 0000000000..56a55e4e9b
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/moduleapi/qobjectModuleApiCaching.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.0
+
+import Qt.test 1.0 as QtTest // module API installed into existing uri
+import Qt.test.qobjectApiParented 1.0 as QtTestParentedQObjectApi // qobject (with parent) module API installed into a new uri
+
+QtObject {
+ property int existingUriTest: QtTest.qobjectTestProperty
+ property int qobjectParentedTest: QtTestParentedQObjectApi.qobjectTestProperty
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/moduleapi/qobjectModuleApiEnums.qml b/tests/auto/qml/qqmlecmascript/data/moduleapi/qobjectModuleApiEnums.qml
new file mode 100644
index 0000000000..da5ffd5e76
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/moduleapi/qobjectModuleApiEnums.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+import Qt.test.qobjectApi 1.0 as QtTestQObjectApi // qobject module API installed into new uri
+
+QtObject {
+ property int enumValue: QtTestQObjectApi.EnumValue2;
+ property int enumMethod: QtTestQObjectApi.qobjectEnumTestMethod(QtTestQObjectApi.EnumValue1);
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/moduleapi/qobjectModuleApiWriting.qml b/tests/auto/qml/qqmlecmascript/data/moduleapi/qobjectModuleApiWriting.qml
new file mode 100644
index 0000000000..be647ca57f
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/moduleapi/qobjectModuleApiWriting.qml
@@ -0,0 +1,26 @@
+import QtQuick 2.0
+import Qt.test 1.0 as QtTest // qobject module API installed into existing uri
+
+QtObject {
+ property int firstProperty: 1
+ property int secondProperty: 2
+ property int readOnlyProperty: QtTest.qobjectTestProperty
+ property int writableProperty: QtTest.qobjectTestWritableProperty
+
+ onFirstPropertyChanged: {
+ // In this case, we want to attempt to set the module API property.
+ // This should fail, as the module API property is read only.
+ if (firstProperty != QtTest.qobjectTestProperty) {
+ QtTest.qobjectTestProperty = firstProperty; // should silently fail.
+ }
+ }
+
+ onSecondPropertyChanged: {
+ // In this case, we want to attempt to set the module API property.
+ // This should succeed, as the module API property is writable.
+ if (secondProperty != QtTest.qobjectTestWritableProperty) {
+ QtTest.qobjectTestWritableProperty = secondProperty; // should succeed.
+ }
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/moduleapi/scriptModuleApi.qml b/tests/auto/qml/qqmlecmascript/data/moduleapi/scriptModuleApi.qml
new file mode 100644
index 0000000000..7c4e20489d
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/moduleapi/scriptModuleApi.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+import Qt.test.scriptApi 1.0 as QtTestScriptApi // script module API installed into new uri
+
+QtObject {
+ property int scriptTest: QtTestScriptApi.scriptTestProperty // script module api's only provide properties.
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/moduleapi/scriptModuleApiCaching.qml b/tests/auto/qml/qqmlecmascript/data/moduleapi/scriptModuleApiCaching.qml
new file mode 100644
index 0000000000..90974b5969
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/moduleapi/scriptModuleApiCaching.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+import Qt.test.scriptApi 1.0 as QtTestScriptApi // script module API installed into new uri
+
+QtObject {
+ property int scriptTest: QtTestScriptApi.scriptTestProperty
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/moduleapi/scriptModuleApiWriting.qml b/tests/auto/qml/qqmlecmascript/data/moduleapi/scriptModuleApiWriting.qml
new file mode 100644
index 0000000000..02461d59ed
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/moduleapi/scriptModuleApiWriting.qml
@@ -0,0 +1,32 @@
+import QtQuick 2.0
+import Qt.test.scriptApi 1.0 as QtTestScriptApi
+import Qt.test.scriptApi 2.0 as QtTestScriptApi2
+
+QtObject {
+ property int firstProperty
+ property int readBack
+
+ property int secondProperty
+ property int unchanged
+
+ onFirstPropertyChanged: {
+ if (QtTestScriptApi.scriptTestProperty != firstProperty) {
+ QtTestScriptApi.scriptTestProperty = firstProperty;
+ readBack = QtTestScriptApi.scriptTestProperty;
+ }
+ }
+
+ onSecondPropertyChanged: {
+ if (QtTestScriptApi2.scriptTestProperty != secondProperty) {
+ QtTestScriptApi2.scriptTestProperty = secondProperty;
+ unchanged = QtTestScriptApi2.scriptTestProperty;
+ }
+ }
+
+ Component.onCompleted: {
+ firstProperty = QtTestScriptApi.scriptTestProperty;
+ readBack = QtTestScriptApi.scriptTestProperty;
+ secondProperty = QtTestScriptApi2.scriptTestProperty;
+ unchanged = QtTestScriptApi2.scriptTestProperty;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/multiEngineObject.qml b/tests/auto/qml/qqmlecmascript/data/multiEngineObject.qml
new file mode 100644
index 0000000000..e349ced98f
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/multiEngineObject.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+QtObject {
+ property string test: thing.stringProperty
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/noSpuriousWarningsAtShutdown.2.qml b/tests/auto/qml/qqmlecmascript/data/noSpuriousWarningsAtShutdown.2.qml
new file mode 100644
index 0000000000..23276f778d
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/noSpuriousWarningsAtShutdown.2.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+
+ Item {}
+
+ SpuriousWarning {}
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/noSpuriousWarningsAtShutdown.qml b/tests/auto/qml/qqmlecmascript/data/noSpuriousWarningsAtShutdown.qml
new file mode 100644
index 0000000000..b4a417e04e
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/noSpuriousWarningsAtShutdown.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+
+ property int childrenCount: root.children.length
+
+ Item {}
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/nonExistentAttachedObject.qml b/tests/auto/qml/qqmlecmascript/data/nonExistentAttachedObject.qml
new file mode 100644
index 0000000000..f9585db009
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/nonExistentAttachedObject.qml
@@ -0,0 +1,5 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ stringProperty: MyQmlContainer.prop
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/nonNotifyable.qml b/tests/auto/qml/qqmlecmascript/data/nonNotifyable.qml
new file mode 100644
index 0000000000..2b8b113c34
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/nonNotifyable.qml
@@ -0,0 +1,6 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ id: root
+ property int test: root.value
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/nonscriptable.qml b/tests/auto/qml/qqmlecmascript/data/nonscriptable.qml
new file mode 100644
index 0000000000..e96df6b40e
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/nonscriptable.qml
@@ -0,0 +1,19 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+MyQmlObject {
+ id: root
+
+ property bool readOk: false;
+ property bool writeOk: false
+
+ Component.onCompleted: {
+ readOk = (root.nonscriptable == undefined);
+
+ try {
+ root.nonscriptable = 10
+ } catch (e) {
+ writeOk = true;
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/nullObjectBinding.qml b/tests/auto/qml/qqmlecmascript/data/nullObjectBinding.qml
new file mode 100644
index 0000000000..1aee7a1670
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/nullObjectBinding.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+
+QtObject {
+ property QtObject test
+ test: if (1) model
+ property ListModel model
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/numberAssignment.qml b/tests/auto/qml/qqmlecmascript/data/numberAssignment.qml
new file mode 100644
index 0000000000..30a77e8aed
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/numberAssignment.qml
@@ -0,0 +1,18 @@
+import Qt.test 1.0
+
+NumberAssignment {
+ test1: if (1) 6.7
+ test2: if (1) "6.7"
+ test3: if (1) 6
+ test4: if (1) "6"
+
+ test5: if (1) 6.7
+ test6: if (1) "6.7"
+ test7: if (1) 6
+ test8: if (1) "6"
+
+ test9: if (1) 6.7
+ test10: if (1) "6.7"
+ test11: if (1) 6
+ test12: if (1) "6"
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/objectConversion.qml b/tests/auto/qml/qqmlecmascript/data/objectConversion.qml
new file mode 100644
index 0000000000..67fc342db3
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/objectConversion.qml
@@ -0,0 +1,16 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 360
+ height: 360
+
+ function circularObject() {
+ var a = {}
+ var b = {}
+
+ a.test = 100;
+ a.c = b;
+ b.c = a;
+ return a;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/objectName.qml b/tests/auto/qml/qqmlecmascript/data/objectName.qml
new file mode 100644
index 0000000000..20b9ec2935
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/objectName.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+
+QtObject {
+ objectName: "hello"
+
+ property string test1: objectName
+ property string test2: objectName.substr(1, 3)
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/objectsCompareAsEqual.qml b/tests/auto/qml/qqmlecmascript/data/objectsCompareAsEqual.qml
new file mode 100644
index 0000000000..845f74b1aa
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/objectsCompareAsEqual.qml
@@ -0,0 +1,15 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+
+ property variant item: child
+ Item { id: child }
+
+ property bool test1: child == child
+ property bool test2: child.parent == root
+ property bool test3: root != child
+ property bool test4: item == child
+ property bool test5: item != root
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/objectsPassThroughSignals.qml b/tests/auto/qml/qqmlecmascript/data/objectsPassThroughSignals.qml
new file mode 100644
index 0000000000..98f9e05bdf
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/objectsPassThroughSignals.qml
@@ -0,0 +1,18 @@
+import QtQuick 2.0
+
+QtObject {
+ id: root
+
+ property bool test: false
+
+ signal mysignal(variant object);
+ function myslot(object)
+ {
+ test = (object == root);
+ }
+
+ Component.onCompleted: {
+ mysignal.connect(this, myslot);
+ mysignal(root);
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/outerBindingOverridesInnerBinding.qml b/tests/auto/qml/qqmlecmascript/data/outerBindingOverridesInnerBinding.qml
new file mode 100644
index 0000000000..090c948f26
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/outerBindingOverridesInnerBinding.qml
@@ -0,0 +1,15 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ id: obj
+ property alias c1: myConstants.c1
+ property alias c2: myConstants.c2
+ property int c3: 0
+
+ objectProperty: ConstantsOverrideBindings {
+ id: myConstants
+ c2: obj.c3
+ }
+
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/ownership.qml b/tests/auto/qml/qqmlecmascript/data/ownership.qml
new file mode 100644
index 0000000000..855a264995
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/ownership.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+QtObject {
+ Component.onCompleted: { var a = getObject(); a = null; }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/propertyAssignmentErrors.qml b/tests/auto/qml/qqmlecmascript/data/propertyAssignmentErrors.qml
new file mode 100644
index 0000000000..34523ec1c7
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/propertyAssignmentErrors.qml
@@ -0,0 +1,29 @@
+import QtQuick 2.0
+
+QtObject {
+ id: root
+
+ property int a
+ property variant b
+
+ property bool test1: false;
+ property bool test2: false;
+
+ Component.onCompleted: {
+ try {
+ root.a = undefined;
+ } catch(e) {
+ if (e.message == "Cannot assign [undefined] to int" &&
+ e.stack.indexOf("propertyAssignmentErrors.qml:14") != -1)
+ root.test1 = true;
+ }
+
+ try {
+ root.a = "Hello";
+ } catch(e) {
+ if (e.message == "Cannot assign QString to int" &&
+ e.stack.indexOf("propertyAssignmentErrors.qml:22") != -1)
+ root.test2 = true;
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/propertySplicing.qml b/tests/auto/qml/qqmlecmascript/data/propertySplicing.qml
new file mode 100644
index 0000000000..53711db3f4
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/propertySplicing.qml
@@ -0,0 +1,10 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+MyDerivedObject {
+ property bool test: false
+
+ Component.onCompleted: {
+ test = intProperty()
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVar.1.qml b/tests/auto/qml/qqmlecmascript/data/propertyVar.1.qml
new file mode 100644
index 0000000000..219e61bf91
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/propertyVar.1.qml
@@ -0,0 +1,22 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+ property bool test: false
+
+ property var car: new vehicle(4);
+ property int wheelCount: car.wheels
+
+ function vehicle(wheels) {
+ this.wheels = wheels;
+ }
+
+ Component.onCompleted: {
+ car.wheels = 6; // not bindable, wheelCount shouldn't update
+
+ if (car.wheels != 6) return;
+ if (wheelCount != 4) return;
+
+ test = true;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVar.10.qml b/tests/auto/qml/qqmlecmascript/data/propertyVar.10.qml
new file mode 100644
index 0000000000..ac7f2bed57
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/propertyVar.10.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+
+PropertyVarBaseItem {
+ property bool test: false
+ Component.onCompleted: {
+ test = true;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVar.2.qml b/tests/auto/qml/qqmlecmascript/data/propertyVar.2.qml
new file mode 100644
index 0000000000..2ac4807ec5
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/propertyVar.2.qml
@@ -0,0 +1,24 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+ property bool test: false
+
+ property var truck: new vehicle(8);
+ property int wheelCount: truck.wheels
+
+ function vehicle(wheels) {
+ this.wheels = wheels;
+ }
+
+ Component.onCompleted: {
+ if (wheelCount != 8) return;
+
+ // not bindable, but wheelCount will update because truck itself changed.
+ truck = new vehicle(12);
+
+ if (wheelCount != 12) return;
+
+ test = true;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVar.3.qml b/tests/auto/qml/qqmlecmascript/data/propertyVar.3.qml
new file mode 100644
index 0000000000..cf6a651639
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/propertyVar.3.qml
@@ -0,0 +1,19 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+ property bool test: false
+
+ property var jsint: 4
+ property int bound: jsint + 5
+
+ Component.onCompleted: {
+ if (bound != 9) return;
+
+ jsint = jsint + 1;
+
+ if (bound != 10) return;
+
+ test = true;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVar.4.qml b/tests/auto/qml/qqmlecmascript/data/propertyVar.4.qml
new file mode 100644
index 0000000000..82fc225e71
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/propertyVar.4.qml
@@ -0,0 +1,18 @@
+import QtQuick 2.0
+
+Item {
+ property bool test: false
+
+ property var items: [1, 2, 3, "four", "five"]
+ property int bound: items[0]
+
+ Component.onCompleted: {
+ if (bound != 1) return;
+
+ items[0] = 10 // bound should remain 1
+
+ if (bound != 1) return;
+
+ test = true;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVar.5.qml b/tests/auto/qml/qqmlecmascript/data/propertyVar.5.qml
new file mode 100644
index 0000000000..a5c7812289
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/propertyVar.5.qml
@@ -0,0 +1,18 @@
+import QtQuick 2.0
+
+Item {
+ property bool test: false
+
+ property var attributes: { 'color': 'red', 'width': 100 }
+ property int bound: attributes.width
+
+ Component.onCompleted: {
+ if (bound != 100) return;
+
+ attributes.width = 200 // bound should remain 100
+
+ if (bound != 100) return;
+
+ test = true;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVar.6.qml b/tests/auto/qml/qqmlecmascript/data/propertyVar.6.qml
new file mode 100644
index 0000000000..060d24e7bc
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/propertyVar.6.qml
@@ -0,0 +1,27 @@
+import QtQuick 2.0
+
+Item {
+ property bool test: false
+
+ property var items: [1, 2, 3, "four", "five"]
+ property int bound: items[0]
+ property var funcs: [(function() { return 6; })]
+ property int bound2: funcs[0]()
+
+ function returnTwenty() {
+ return 20;
+ }
+
+ Component.onCompleted: {
+ if (bound != 1) return false;
+ if (bound2 != 6) return false;
+
+ items = [10, 2, 3, "four", "five"] // bound should now be 10
+ funcs = [returnTwenty] // bound2 should now be 20
+
+ if (bound != 10) return false;
+ if (bound2 != 20) return false;
+
+ test = true;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVar.7.qml b/tests/auto/qml/qqmlecmascript/data/propertyVar.7.qml
new file mode 100644
index 0000000000..1d6c8c0a37
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/propertyVar.7.qml
@@ -0,0 +1,18 @@
+import QtQuick 2.0
+
+Item {
+ property bool test: false
+
+ property var attributes: { 'color': 'red', 'width': 100 }
+ property int bound: attributes.width
+
+ Component.onCompleted: {
+ if (bound != 100) return;
+
+ attributes = { 'color': 'blue', 'width': 200 } // bound should now be 200
+
+ if (bound != 200) return;
+
+ test = true;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVar.8.qml b/tests/auto/qml/qqmlecmascript/data/propertyVar.8.qml
new file mode 100644
index 0000000000..a9f73db402
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/propertyVar.8.qml
@@ -0,0 +1,12 @@
+import QtQuick 2.0
+
+Item {
+ property bool test: false
+
+ property var literalValue: 6
+
+ Component.onCompleted: {
+ if (literalValue != 6) return;
+ test = true;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVar.9.qml b/tests/auto/qml/qqmlecmascript/data/propertyVar.9.qml
new file mode 100644
index 0000000000..f5aca28417
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/propertyVar.9.qml
@@ -0,0 +1,19 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ property bool test: false
+
+ MyQmlObject {
+ id: qmlobject
+ intProperty: 5
+ }
+ property var qobjectVar: qmlobject
+ property int bound: qobjectVar.intProperty
+
+ Component.onCompleted: {
+ if (bound != 5) return;
+
+ test = true;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVar.circular.2.qml b/tests/auto/qml/qqmlecmascript/data/propertyVar.circular.2.qml
new file mode 100644
index 0000000000..93c44afcc9
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/propertyVar.circular.2.qml
@@ -0,0 +1,26 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+ objectName: "separateRootObject"
+ property var vp
+
+ function constructGarbage() {
+ var retn = 1;
+ var component = Qt.createComponent("PropertyVarCircularComponent3.qml");
+ if (component.status == Component.Ready) {
+ retn = component.createObject(null); // has JavaScript ownership
+ }
+ return retn;
+ }
+
+ function assignCircular() {
+ vp = constructGarbage();
+ gc();
+ }
+
+ function deassignCircular() {
+ vp = 2;
+ gc();
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVar.circular.qml b/tests/auto/qml/qqmlecmascript/data/propertyVar.circular.qml
new file mode 100644
index 0000000000..171d7747cd
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/propertyVar.circular.qml
@@ -0,0 +1,44 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ id: testCircular
+
+ property var varProperty
+ property variant canaryResource
+ property int canaryInt
+
+ function constructGarbage() {
+ var retn = 1;
+ var component = Qt.createComponent("PropertyVarCircularComponent.qml");
+ if (component.status == Component.Ready) {
+ retn = component.createObject(null); // has JavaScript ownership
+ }
+ return retn;
+ }
+
+ function deassignCanaryResource() {
+ canaryResource = 1;
+ gc();
+ }
+
+ function assignCircular() {
+ varProperty = constructGarbage();
+ canaryResource = varProperty.vp.vp.vp.vp.memoryHog;
+ canaryInt = varProperty.vp.vp.vp.vp.fifthCanary; // == 5
+ gc();
+ }
+
+ function deassignCircular() {
+ canaryInt = 2;
+ varProperty = 2;
+ gc();
+ }
+
+ function assignThenDeassign() {
+ varProperty = constructGarbage();
+ varProperty = 2;
+ gc();
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVar.inherit.qml b/tests/auto/qml/qqmlecmascript/data/propertyVar.inherit.qml
new file mode 100644
index 0000000000..abd0dd7c04
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/propertyVar.inherit.qml
@@ -0,0 +1,34 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ id: testInheritance
+
+ property var varProperty
+
+ function constructGarbage() {
+ var retn = 1;
+ var component = Qt.createComponent("PropertyVarInheritanceComponent.qml");
+ if (component.status == Component.Ready) {
+ retn = component.createObject(null); // has JavaScript ownership
+ }
+ return retn;
+ }
+
+ function assignCircular() {
+ varProperty = constructGarbage();
+ gc();
+ }
+
+ function deassignCircular() {
+ varProperty = 2;
+ gc();
+ }
+
+ function assignThenDeassign() {
+ varProperty = constructGarbage();
+ varProperty = 2;
+ gc();
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVar.reparent.qml b/tests/auto/qml/qqmlecmascript/data/propertyVar.reparent.qml
new file mode 100644
index 0000000000..7b3df674f1
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/propertyVar.reparent.qml
@@ -0,0 +1,27 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+ objectName: "separateRootObject"
+ property var vp
+
+ function constructGarbage() {
+ var retn = 1;
+ var component = Qt.createComponent("PropertyVarOwnershipComponent.qml");
+ if (component.status == Component.Ready) {
+ retn = component.createObject(null); // has JavaScript ownership
+ }
+ return retn;
+ }
+
+ function assignVarProp() {
+ vp = constructGarbage();
+ gc();
+ }
+
+ function deassignVarProp() {
+ vp = 2;
+ gc();
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVarCpp.qml b/tests/auto/qml/qqmlecmascript/data/propertyVarCpp.qml
new file mode 100644
index 0000000000..cd3147f565
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/propertyVarCpp.qml
@@ -0,0 +1,17 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ id: testOwnership
+ property int intProperty: 10
+ property var varProperty: intProperty
+ property var varProperty2: false
+ property var varBound: varProperty + 5
+ property int intBound: varProperty + 5
+ property var jsobject: new vehicle(4)
+
+ function vehicle(wheels) {
+ this.wheels = wheels;
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVarImplicitOwnership.qml b/tests/auto/qml/qqmlecmascript/data/propertyVarImplicitOwnership.qml
new file mode 100644
index 0000000000..9cebded932
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/propertyVarImplicitOwnership.qml
@@ -0,0 +1,26 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+ objectName: "separateRootObject"
+ property var vp
+
+ function constructGarbage() {
+ var retn = 1;
+ var component = Qt.createComponent("PropertyVarCircularComponent4.qml");
+ if (component.status == Component.Ready) {
+ retn = component.createObject(null); // has JavaScript ownership
+ }
+ return retn;
+ }
+
+ function assignCircular() {
+ vp = constructGarbage();
+ gc();
+ }
+
+ function deassignCircular() {
+ vp = 2;
+ gc();
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVarOwnership.2.qml b/tests/auto/qml/qqmlecmascript/data/propertyVarOwnership.2.qml
new file mode 100644
index 0000000000..14d4f9fd27
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/propertyVarOwnership.2.qml
@@ -0,0 +1,24 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ id: testOwnership
+ property bool test: false
+
+ property int dummyProperty // Tests for non-interference of other properties
+ property var varProperty
+
+ function runTest() {
+ if (varProperty != undefined) return;
+ varProperty = { a: 10, b: 11 }
+ if (varProperty.a != 10) return;
+
+ gc(); // Shouldn't collect
+
+ if (varProperty.a != 10) return;
+
+ test = true;
+ }
+}
+
+
diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVarOwnership.3.qml b/tests/auto/qml/qqmlecmascript/data/propertyVarOwnership.3.qml
new file mode 100644
index 0000000000..d5b449c938
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/propertyVarOwnership.3.qml
@@ -0,0 +1,31 @@
+import QtQuick 2.0
+
+Item {
+ property var object
+
+ property bool test1: false
+ property bool test2: false
+
+ // Test methods are executed in sequential order
+
+ function runTest() {
+ var c = Qt.createComponent("propertyVarOwnership.3.type.qml");
+ object = c.createObject();
+
+ if (object.dummy != 10) return;
+ test1 = true;
+ }
+
+ // Run gc() from C++
+
+ function runTest2() {
+ if (object.dummy != 10) return;
+
+ object = undefined;
+ if (object != undefined) return;
+
+ test2 = true;
+ }
+
+ // Run gc() from C++ - QObject should be collected
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVarOwnership.3.type.qml b/tests/auto/qml/qqmlecmascript/data/propertyVarOwnership.3.type.qml
new file mode 100644
index 0000000000..3406553b91
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/propertyVarOwnership.3.type.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+QtObject {
+ property int dummy: 10
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVarOwnership.4.qml b/tests/auto/qml/qqmlecmascript/data/propertyVarOwnership.4.qml
new file mode 100644
index 0000000000..1eba36ce81
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/propertyVarOwnership.4.qml
@@ -0,0 +1,25 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+
+ property var object
+
+ property bool test: false
+
+ Component.onCompleted: {
+ var c = Qt.createComponent("propertyVarOwnership.4.type1.qml");
+ object = c.createObject();
+
+ if (object.dummy != 10) return;
+ if (object.test != true) return;
+
+ object.creatorRef = root;
+
+ test = true;
+ }
+
+ function runTest() {
+ object = null;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVarOwnership.4.type1.qml b/tests/auto/qml/qqmlecmascript/data/propertyVarOwnership.4.type1.qml
new file mode 100644
index 0000000000..9a29b6e17f
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/propertyVarOwnership.4.type1.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.0
+
+// Has a self reference in selfRef, and a reference to propertyVarOwnership.4.qml in creatorRef
+Item {
+ id: root
+
+ property var creatorRef
+ property var selfRef
+ property var object
+
+ property int dummy: 10
+ property bool test: false
+
+ Component.onCompleted: {
+ selfRef = root;
+
+ var c = Qt.createComponent("propertyVarOwnership.4.type2.qml");
+ object = c.createObject();
+ object.creatorRef = root;
+
+ test = true;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVarOwnership.4.type2.qml b/tests/auto/qml/qqmlecmascript/data/propertyVarOwnership.4.type2.qml
new file mode 100644
index 0000000000..f82b8a1c1e
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/propertyVarOwnership.4.type2.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+
+// Has a reference to propertyVarOwnership.4.type1.qml in creatorRef
+Item {
+ property var creatorRef
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/propertyVarOwnership.qml b/tests/auto/qml/qqmlecmascript/data/propertyVarOwnership.qml
new file mode 100644
index 0000000000..7b99c4b6ad
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/propertyVarOwnership.qml
@@ -0,0 +1,22 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ id: testOwnership
+ property bool test: false
+
+ property var varProperty
+
+ function runTest() {
+ if (varProperty != undefined) return;
+ varProperty = { a: 10, b: 11 }
+ if (varProperty.a != 10) return;
+
+ gc(); // Shouldn't collect
+
+ if (varProperty.a != 10) return;
+
+ test = true;
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/qlistqobjectMethods.qml b/tests/auto/qml/qqmlecmascript/data/qlistqobjectMethods.qml
new file mode 100644
index 0000000000..3c1986d721
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/qlistqobjectMethods.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+
+QtObject {
+ property int test: getObjects().length
+ property bool test2: getObjects()[0].trueProperty
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/qmlHasOwnProperty.qml b/tests/auto/qml/qqmlecmascript/data/qmlHasOwnProperty.qml
new file mode 100644
index 0000000000..12598b3b9f
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/qmlHasOwnProperty.qml
@@ -0,0 +1,72 @@
+import QtQuick 2.0
+import Qt.test 1.0
+import Qt.test.qobjectApi 1.0 as QtTestQObjectApi
+
+Item {
+ id: obj
+ objectName: "objName"
+ property int someIntProperty: 10
+ property bool result: false
+
+ function testHasOwnPropertySuccess()
+ {
+ obj.result = obj.hasOwnProperty("someIntProperty");
+ }
+
+ function testHasOwnPropertyFailure()
+ {
+ obj.result = obj.hasOwnProperty("someNonexistentProperty");
+ }
+
+ MyTypeObject {
+ id: typeObj
+ objectName: "typeObj"
+ pointProperty: Qt.point(34, 29)
+ variantProperty: Qt.vector3d(1, 2, 3)
+ stringProperty: "test string"
+ property list<Rectangle> listProperty: [ Rectangle { width: 10; height: 10 } ]
+ property list<Rectangle> emptyListProperty
+
+ property bool valueTypeHasOwnProperty
+ property bool valueTypeHasOwnProperty2
+ property bool variantTypeHasOwnProperty
+ property bool stringTypeHasOwnProperty
+ property bool listTypeHasOwnProperty
+ property bool listAtValidHasOwnProperty
+ property bool emptyListTypeHasOwnProperty
+ property bool enumTypeHasOwnProperty
+ property bool typenameHasOwnProperty
+ property bool typenameHasOwnProperty2
+ property bool moduleApiTypeHasOwnProperty
+ property bool moduleApiPropertyTypeHasOwnProperty
+ function testHasOwnPropertySuccess() {
+ valueTypeHasOwnProperty = !typeObj.pointProperty.hasOwnProperty("nonexistentpropertyname");
+ valueTypeHasOwnProperty2 = typeObj.pointProperty.hasOwnProperty("x"); // should be true
+ variantTypeHasOwnProperty = !typeObj.variantProperty.hasOwnProperty("nonexistentpropertyname");
+ stringTypeHasOwnProperty = !typeObj.stringProperty.hasOwnProperty("nonexistentpropertyname");
+ listTypeHasOwnProperty = !typeObj.listProperty.hasOwnProperty("nonexistentpropertyname");
+ listAtValidHasOwnProperty = !typeObj.listProperty[0].hasOwnProperty("nonexistentpropertyname");
+ emptyListTypeHasOwnProperty = !typeObj.emptyListProperty.hasOwnProperty("nonexistentpropertyname");
+ enumTypeHasOwnProperty = !MyTypeObject.EnumVal1.hasOwnProperty("nonexistentpropertyname");
+ typenameHasOwnProperty = !MyTypeObject.hasOwnProperty("nonexistentpropertyname");
+ typenameHasOwnProperty2 = MyTypeObject.hasOwnProperty("EnumVal1"); // should be true.
+ moduleApiTypeHasOwnProperty = !QtTestQObjectApi.hasOwnProperty("nonexistentpropertyname");
+ moduleApiPropertyTypeHasOwnProperty = !QtTestQObjectApi.qobjectTestProperty.hasOwnProperty("nonexistentpropertyname");
+ }
+
+ property bool enumNonValueHasOwnProperty
+ function testHasOwnPropertyFailureOne() {
+ enumNonValueHasOwnProperty = !MyTypeObject.NonexistentEnumVal.hasOwnProperty("nonexistentpropertyname");
+ }
+
+ property bool moduleApiNonPropertyHasOwnProperty
+ function testHasOwnPropertyFailureTwo() {
+ moduleApiNonPropertyHasOwnProperty = !QtTestQObjectApi.someNonexistentProperty.hasOwnProperty("nonexistentpropertyname");
+ }
+
+ property bool listAtInvalidHasOwnProperty
+ function testHasOwnPropertyFailureThree() {
+ listAtInvalidHasOwnProperty = !typeObj.listProperty[5].hasOwnProperty("nonexistentpropertyname");
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/qmlToString.qml b/tests/auto/qml/qqmlecmascript/data/qmlToString.qml
new file mode 100644
index 0000000000..ac296ce293
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/qmlToString.qml
@@ -0,0 +1,11 @@
+import Qt.test 1.0
+
+MyQmlObject{
+ id: obj
+ objectName: "objName"
+ function testToString()
+ {
+ obj.stringProperty = obj.toString();
+ }
+
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/qobjectConnectionListExceptionHandling.qml b/tests/auto/qml/qqmlecmascript/data/qobjectConnectionListExceptionHandling.qml
new file mode 100644
index 0000000000..acd512a2be
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/qobjectConnectionListExceptionHandling.qml
@@ -0,0 +1,24 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+ property int first: 5
+ property bool test: false
+
+ Item {
+ id: exceptional
+ function exceptionalFunction() {
+ var obj = undefined;
+ var prop = undefined;
+ return obj[prop];
+ }
+ }
+
+ Component.onCompleted: {
+ root["firstChanged"].connect(exceptional.exceptionalFunction);
+ root["firstChanged"].connect(exceptional.exceptionalFunction);
+ root["firstChanged"].connect(exceptional.exceptionalFunction);
+ first = 6;
+ test = true;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/qobjectDerivedArgument.qml b/tests/auto/qml/qqmlecmascript/data/qobjectDerivedArgument.qml
new file mode 100644
index 0000000000..bf4ab6fd7a
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/qobjectDerivedArgument.qml
@@ -0,0 +1,17 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+MyQmlObject {
+ id: root
+ stringProperty: 'hello'
+ property var child
+
+ property bool result: false
+
+ Component.onCompleted: {
+ child = invokable.createMyQmlObject('goodbye');
+
+ result = (invokable.getStringProperty(root) == 'hello') &&
+ (invokable.getStringProperty(child) == 'goodbye');
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/qtbug_10696.qml b/tests/auto/qml/qqmlecmascript/data/qtbug_10696.qml
new file mode 100644
index 0000000000..90263e5124
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/qtbug_10696.qml
@@ -0,0 +1,26 @@
+import QtQuick 2.0
+
+QtObject {
+ property string test: "aaaa"
+ + "bbbb"
+ + "cccc"
+ + "cccc"
+ + "cccc"
+ + "cccc"
+ + "cccc"
+ + "cccc"
+ + "cccc"
+ + "cccc"
+ + "cccc"
+ + "cccc"
+ + "cccc"
+ + "cccc"
+ + "cccc"
+ + "cccc"
+ + "cccc"
+ + "cccc"
+ + "cccc"
+ + "cccc"
+ + "cccc"
+ + "cccc";
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/qtbug_11600.js b/tests/auto/qml/qqmlecmascript/data/qtbug_11600.js
new file mode 100644
index 0000000000..092bc2b041
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/qtbug_11600.js
@@ -0,0 +1 @@
+;
diff --git a/tests/auto/qml/qqmlecmascript/data/qtbug_11600.qml b/tests/auto/qml/qqmlecmascript/data/qtbug_11600.qml
new file mode 100644
index 0000000000..6c7e8806e6
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/qtbug_11600.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+import "qtbug_11600.js" as Test
+
+QtObject {
+ id: goo
+
+ property bool test: undefined == goo.Test
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/qtbug_11606.qml b/tests/auto/qml/qqmlecmascript/data/qtbug_11606.qml
new file mode 100644
index 0000000000..b1b062ed35
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/qtbug_11606.qml
@@ -0,0 +1,12 @@
+import QtQuick 2.0
+
+QtObject {
+ property bool test: false
+ Component.onCompleted: {
+ try {
+ console.log(sorryNoSuchProperty);
+ } catch (e) {
+ test = true;
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/qtbug_20344.qml b/tests/auto/qml/qqmlecmascript/data/qtbug_20344.qml
new file mode 100644
index 0000000000..f490848caf
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/qtbug_20344.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+MyQmlObject {
+ Component.onCompleted: v8function()
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/qtbug_21580.qml b/tests/auto/qml/qqmlecmascript/data/qtbug_21580.qml
new file mode 100644
index 0000000000..dc0066ba3f
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/qtbug_21580.qml
@@ -0,0 +1,22 @@
+import QtQuick 2.0
+
+QtObject {
+ property bool test: false
+
+ property list<QtObject> objects: [
+ QtObject {
+ id: first
+ property alias myAlias: other.myProperty
+ onMyAliasChanged: if (myAlias == 20) test = true
+ },
+ QtObject {
+ id: other
+ property real myProperty
+ }
+ ]
+
+ Component.onCompleted: {
+ other.myProperty = 20;
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/qtbug_21864.js b/tests/auto/qml/qqmlecmascript/data/qtbug_21864.js
new file mode 100644
index 0000000000..e1a688ebbe
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/qtbug_21864.js
@@ -0,0 +1,2 @@
+var a = { b: 10 }
+var test = (typeof a) == "object"
diff --git a/tests/auto/qml/qqmlecmascript/data/qtbug_21864.qml b/tests/auto/qml/qqmlecmascript/data/qtbug_21864.qml
new file mode 100644
index 0000000000..0f972d5459
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/qtbug_21864.qml
@@ -0,0 +1,6 @@
+import "qtbug_21864.js" as Test
+import QtQuick 2.0
+
+QtObject {
+ property bool test: Test.test
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/qtbug_22464.qml b/tests/auto/qml/qqmlecmascript/data/qtbug_22464.qml
new file mode 100644
index 0000000000..19f26736f1
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/qtbug_22464.qml
@@ -0,0 +1,15 @@
+import QtQuick 2.0
+
+QtObject {
+ property alias value: inner.value
+ property bool test: false
+
+ property variant dummy: QtObject {
+ id: inner
+ property variant value: Qt.rgba(1, 1, 0, 1);
+ }
+
+ Component.onCompleted: {
+ test = (value == Qt.rgba(1, 1, 0, 1));
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/qtbug_22679.qml b/tests/auto/qml/qqmlecmascript/data/qtbug_22679.qml
new file mode 100644
index 0000000000..b38a84b4c0
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/qtbug_22679.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+
+QtObject {
+ function accessContextProperty() {
+ for (var i = 0; i < contextProp.stringProperty.length; ++i) ;
+ }
+
+ Component.onCompleted: {
+ for (var i = 0; i < 1000; ++i)
+ accessContextProperty();
+ // Shouldn't cause "Illegal invocation" error.
+ gc();
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/qtbug_22843.js b/tests/auto/qml/qqmlecmascript/data/qtbug_22843.js
new file mode 100644
index 0000000000..6d19fe0571
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/qtbug_22843.js
@@ -0,0 +1,5 @@
+
+function func()
+{
+ isFinite() )
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/qtbug_22843.library.js b/tests/auto/qml/qqmlecmascript/data/qtbug_22843.library.js
new file mode 100644
index 0000000000..1a7c8a2e6e
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/qtbug_22843.library.js
@@ -0,0 +1,5 @@
+.pragma library
+function func()
+{
+ isFinite() )
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/qtbug_22843.library.qml b/tests/auto/qml/qqmlecmascript/data/qtbug_22843.library.qml
new file mode 100644
index 0000000000..281765bff6
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/qtbug_22843.library.qml
@@ -0,0 +1,6 @@
+import "qtbug_22843.library.js" as MyScript
+import QtQuick 2.0
+
+QtObject {
+ Component.onCompleted: MyScript.func()
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/qtbug_22843.qml b/tests/auto/qml/qqmlecmascript/data/qtbug_22843.qml
new file mode 100644
index 0000000000..90a47c0f4b
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/qtbug_22843.qml
@@ -0,0 +1,6 @@
+import "qtbug_22843.js" as MyScript
+import QtQuick 2.0
+
+QtObject {
+ Component.onCompleted: MyScript.func()
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/qtbug_9792.qml b/tests/auto/qml/qqmlecmascript/data/qtbug_9792.qml
new file mode 100644
index 0000000000..9ac44308c6
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/qtbug_9792.qml
@@ -0,0 +1,5 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ onBasicSignal: print("Hello world!");
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/qtcreatorbug_1289.qml b/tests/auto/qml/qqmlecmascript/data/qtcreatorbug_1289.qml
new file mode 100644
index 0000000000..90711c8d09
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/qtcreatorbug_1289.qml
@@ -0,0 +1,13 @@
+import QtQuick 2.0
+
+QtObject {
+ id: root
+ property QtObject object: QtObject {
+ id: nested
+ property QtObject nestedObject
+ }
+
+ Component.onCompleted: {
+ nested.nestedObject = root;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/readonlyDeclaration.qml b/tests/auto/qml/qqmlecmascript/data/readonlyDeclaration.qml
new file mode 100644
index 0000000000..5377d2dcbf
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/readonlyDeclaration.qml
@@ -0,0 +1,45 @@
+import QtQuick 2.0
+
+QtObject {
+ property int dummy: 13
+
+ readonly property int test1: 19
+ readonly property int test2: dummy * 49
+ readonly property alias test3: other.test
+
+ property bool test: false
+
+ property var dummyObj: QtObject {
+ id: other
+ property int test: 9
+ }
+
+ Component.onCompleted: {
+ if (test1 != 19) return;
+ if (test2 != 637) return;
+ if (test3 != 9) return;
+
+ var caught = false;
+
+ caught = false;
+ try { test1 = 13 } catch (e) { caught = true; }
+ if (!caught) return;
+
+ caught = false;
+ try { test2 = 13 } catch (e) { caught = true; }
+ if (!caught) return;
+
+ caught = false;
+ try { test3 = 13 } catch (e) { caught = true; }
+ if (!caught) return;
+
+ other.test = 13;
+ dummy = 9;
+
+ if (test1 != 19) return;
+ if (test2 != 441) return;
+ if (test3 != 13) return;
+
+ test = true;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/realToInt.qml b/tests/auto/qml/qqmlecmascript/data/realToInt.qml
new file mode 100644
index 0000000000..a9e7dd2a95
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/realToInt.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+MyQmlObject {
+ function test1() {
+ value = 4.2
+ }
+ function test2() {
+ value = 7.9
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/regExp.2.qml b/tests/auto/qml/qqmlecmascript/data/regExp.2.qml
new file mode 100644
index 0000000000..68cca5733b
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/regExp.2.qml
@@ -0,0 +1,7 @@
+import Qt.test 1.0
+
+MyQmlObject{
+ id: obj
+ objectName: "obj"
+ regExp: "[a-zA-z]"
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/regExp.qml b/tests/auto/qml/qqmlecmascript/data/regExp.qml
new file mode 100644
index 0000000000..0dc404b5db
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/regExp.qml
@@ -0,0 +1,7 @@
+import Qt.test 1.0
+
+MyQmlObject{
+ id: obj
+ objectName: "obj"
+ regExp: /[a-zA-z]/
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/remote_file.js b/tests/auto/qml/qqmlecmascript/data/remote_file.js
new file mode 100644
index 0000000000..1b123aee61
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/remote_file.js
@@ -0,0 +1,2 @@
+myvar = 13;
+test5 = true;
diff --git a/tests/auto/qml/qqmlecmascript/data/rewriteMultiLineStrings.qml b/tests/auto/qml/qqmlecmascript/data/rewriteMultiLineStrings.qml
new file mode 100644
index 0000000000..1ae1b162b2
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/rewriteMultiLineStrings.qml
@@ -0,0 +1,35 @@
+import QtQuick 2.0
+
+Item {
+ id: root;
+ property bool test: str == str2 && (txt != null && txt.str == root.str)
+ property Text txt: null
+ //Constant doesn't hit rewriter
+ property string str: 'same
+multiline
+string 5 !'
+ property string str2: '';
+ Component {
+ id: comp
+ Text {
+ property var value: 1
+ property string str: 'same
+multiline
+string ' + value + " !"
+ Component.onCompleted: { //Separate codepath for signal handers in rewriter
+ root.str2 = 'same
+multiline
+string ' + value + " !"
+ }
+ }
+ }
+ Component.onCompleted: txt = comp.createObject(root,{"value" : 5})
+ /*
+ Timer {
+ interval: 1000
+ running: true
+ repeat: true
+ onTriggered: console.debug( "Test: " + test + '\n' + str + '\n:\n' + str2 + "\n:\n" + txt.str)
+ }
+ */
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/rewriteMultiLineStrings_crlf.1.qml b/tests/auto/qml/qqmlecmascript/data/rewriteMultiLineStrings_crlf.1.qml
new file mode 100644
index 0000000000..f84ba8c722
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/rewriteMultiLineStrings_crlf.1.qml
@@ -0,0 +1,13 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: root
+
+ Component.onCompleted: {
+ var o = Qt.createQmlObject("import QtQuick 2.0; \
+ \
+ Item { \
+ property bool b: true; \
+ }", root, "Instance")
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceCopy.var.qml b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopy.var.qml
new file mode 100644
index 0000000000..805655fc17
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopy.var.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+// Here we import a scarce resource directly.
+// The instance has a property which is a copy
+// of the scarce resource, so it should not be
+// detached (but we should automatically release
+// the resource from our engine internal list).
+
+QtObject {
+ property MyScarceResourceObject a;
+ a: MyScarceResourceObject { id: scarceResourceProvider }
+ property var scarceResourceCopy: scarceResourceProvider.scarceResource
+} \ No newline at end of file
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceCopy.variant.qml b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopy.variant.qml
new file mode 100644
index 0000000000..ee5b05b28a
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopy.variant.qml
@@ -0,0 +1,15 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+// Here we import a scarce resource directly.
+// The instance has a property which is a copy
+// of the scarce resource, so it should not be
+// detached (but we should automatically release
+// the resource from our engine internal list).
+
+QtObject {
+ property MyScarceResourceObject a;
+ a: MyScarceResourceObject { id: scarceResourceProvider }
+ property variant scarceResourceCopy: scarceResourceProvider.scarceResource
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyFromJs.var.qml b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyFromJs.var.qml
new file mode 100644
index 0000000000..09868e5e7c
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyFromJs.var.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+import Qt.test 1.0
+import "scarceResourceTest.var.js" as ScarceResourceProviderJs
+
+// Here we import a scarce resource directly, from JS module.
+// It is not preserved or released manually, so it should be
+// automatically released once evaluation of the binding
+// is complete.
+
+QtObject {
+ property MyScarceResourceObject a;
+ a: MyScarceResourceObject { id: scarceResourceProvider }
+ property var scarceResourceCopy: ScarceResourceProviderJs.importScarceResource(scarceResourceProvider)
+} \ No newline at end of file
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyFromJs.variant.qml b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyFromJs.variant.qml
new file mode 100644
index 0000000000..a1ebeb4073
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyFromJs.variant.qml
@@ -0,0 +1,15 @@
+import QtQuick 2.0
+import Qt.test 1.0
+import "scarceResourceTest.variant.js" as ScarceResourceProviderJs
+
+// Here we import a scarce resource directly, from JS module.
+// It is not preserved or released manually, so it should be
+// automatically released once evaluation of the binding
+// is complete.
+
+QtObject {
+ property MyScarceResourceObject a;
+ a: MyScarceResourceObject { id: scarceResourceProvider }
+ property variant scarceResourceCopy: ScarceResourceProviderJs.importScarceResource(scarceResourceProvider)
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImport.var.js b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImport.var.js
new file mode 100644
index 0000000000..468a6b4f2e
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImport.var.js
@@ -0,0 +1,25 @@
+.import Qt.test 1.0 as JsQtTest
+
+// In this case, the "retn" variable will be evaluated during import.
+// Since the "importScarceResource()" function depends on this variable,
+// we must explicitly preserve the "retn" variable or the scarce
+// resource would automatically be released after import completes
+// but before the binding is evaluated.
+
+var component = Qt.createComponent("scarceResourceCopy.var.qml");
+var scarceResourceElement = component.createObject(null);
+var scarceResourceProvider = scarceResourceElement.a;
+var retn = scarceResourceProvider.scarceResource;
+retn.preserve(); // must preserve manually or it will be released!
+
+function importScarceResource() {
+ // if called prior to calling destroyScarceResource(),
+ // this function should return the preserved scarce resource.
+ // otherwise, it should return an invalid variant.
+ return retn;
+}
+
+function destroyScarceResource() {
+ retn.destroy();
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImport.var.qml b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImport.var.qml
new file mode 100644
index 0000000000..9321481f45
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImport.var.qml
@@ -0,0 +1,18 @@
+import QtQuick 2.0
+import Qt.test 1.0
+import "scarceResourceCopyImport.var.js" as ScarceResourceCopyImportJs
+
+QtObject {
+ // this binding is evaluated once, prior to the resource being released
+ property var scarceResourceImportedCopy: ScarceResourceCopyImportJs.importScarceResource()
+
+ property bool arePropertiesEqual
+ property var scarceResourceAssignedCopyOne;
+ property var scarceResourceAssignedCopyTwo;
+ Component.onCompleted: {
+ scarceResourceAssignedCopyOne = ScarceResourceCopyImportJs.importScarceResource();
+ arePropertiesEqual = (scarceResourceAssignedCopyOne == scarceResourceImportedCopy);
+ ScarceResourceCopyImportJs.destroyScarceResource(); // makes all properties invalid.
+ scarceResourceAssignedCopyTwo = ScarceResourceCopyImportJs.importScarceResource();
+ }
+} \ No newline at end of file
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImport.variant.js b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImport.variant.js
new file mode 100644
index 0000000000..9aeb507487
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImport.variant.js
@@ -0,0 +1,25 @@
+.import Qt.test 1.0 as JsQtTest
+
+// In this case, the "retn" variable will be evaluated during import.
+// Since the "importScarceResource()" function depends on this variable,
+// we must explicitly preserve the "retn" variable or the scarce
+// resource would automatically be released after import completes
+// but before the binding is evaluated.
+
+var component = Qt.createComponent("scarceResourceCopy.variant.qml");
+var scarceResourceElement = component.createObject(null);
+var scarceResourceProvider = scarceResourceElement.a;
+var retn = scarceResourceProvider.scarceResource;
+retn.preserve(); // must preserve manually or it will be released!
+
+function importScarceResource() {
+ // if called prior to calling destroyScarceResource(),
+ // this function should return the preserved scarce resource.
+ // otherwise, it should return an invalid variant.
+ return retn;
+}
+
+function destroyScarceResource() {
+ retn.destroy();
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImport.variant.qml b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImport.variant.qml
new file mode 100644
index 0000000000..e8b53979dd
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImport.variant.qml
@@ -0,0 +1,18 @@
+import QtQuick 2.0
+import Qt.test 1.0
+import "scarceResourceCopyImport.variant.js" as ScarceResourceCopyImportJs
+
+QtObject {
+ // this binding is evaluated once, prior to the resource being released
+ property variant scarceResourceImportedCopy: ScarceResourceCopyImportJs.importScarceResource()
+
+ // this code is evaluated on completion, and so copy one should be valid, copy two invalid.
+ property variant scarceResourceAssignedCopyOne;
+ property variant scarceResourceAssignedCopyTwo;
+ Component.onCompleted: {
+ scarceResourceAssignedCopyOne = ScarceResourceCopyImportJs.importScarceResource();
+ ScarceResourceCopyImportJs.destroyScarceResource();
+ scarceResourceAssignedCopyTwo = ScarceResourceCopyImportJs.importScarceResource();
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportDifferent.var.js b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportDifferent.var.js
new file mode 100644
index 0000000000..000eeddb34
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportDifferent.var.js
@@ -0,0 +1,19 @@
+.import Qt.test 1.0 as JsQtTest
+
+// In this case, we create the returned scarce resource each call,
+// so the object will be different every time it is returned.
+
+var mostRecent
+
+function importScarceResource() {
+ var component = Qt.createComponent("scarceResourceCopy.var.qml");
+ var scarceResourceElement = component.createObject(null);
+ var scarceResourceProvider = scarceResourceElement.a;
+ var retn = scarceResourceProvider.scarceResource;
+ mostRecent = retn;
+ return retn;
+}
+
+function destroyScarceResource() {
+ mostRecent.destroy();
+} \ No newline at end of file
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportDifferent.var.qml b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportDifferent.var.qml
new file mode 100644
index 0000000000..082d132c24
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportDifferent.var.qml
@@ -0,0 +1,22 @@
+import QtQuick 2.0
+import Qt.test 1.0
+import "scarceResourceCopyImportDifferent.var.js" as ScarceResourceCopyImportJs
+
+// in this case, the ScarceResourceCopyImportJs returns a _new_, different
+// scarce resource each time. Invalidating one will not invalidate the others.
+
+QtObject {
+ // this binding is evaluated once, prior to the resource being released
+ property var scarceResourceImportedCopy: ScarceResourceCopyImportJs.importScarceResource()
+
+ // the following properties are assigned on component completion.
+ property bool arePropertiesEqual
+ property var scarceResourceAssignedCopyOne;
+ property var scarceResourceAssignedCopyTwo;
+ Component.onCompleted: {
+ scarceResourceAssignedCopyOne = ScarceResourceCopyImportJs.importScarceResource();
+ arePropertiesEqual = (scarceResourceAssignedCopyOne != scarceResourceImportedCopy); // they're not the same object.
+ ScarceResourceCopyImportJs.destroyScarceResource(); // makes the MOST RECENT resource invalid (ie, assignedCopyOne).
+ scarceResourceAssignedCopyTwo = ScarceResourceCopyImportJs.importScarceResource();
+ }
+} \ No newline at end of file
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportFail.var.js b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportFail.var.js
new file mode 100644
index 0000000000..ba52b323f0
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportFail.var.js
@@ -0,0 +1,19 @@
+.import Qt.test 1.0 as JsQtTest
+
+// In this case, the "retn" variable will be evaluated during import.
+// Since the importScarceResource() function depends on this variable,
+// because we DO NOT call "retn.preserve()", the scarce resource will
+// be released after the import completes but prior to evaluation of
+// any binding which calls "importScarceResource()".
+// Thus, "importScarceResource()" will return a released (invalid)
+// scarce resource.
+
+var component = Qt.createComponent("scarceResourceCopy.var.qml");
+var scarceResourceElement = component.createObject(null);
+var scarceResourceProvider = scarceResourceElement.a;
+var retn = scarceResourceProvider.scarceResource;
+
+function importScarceResource() {
+ return retn; // should return a released (invalid) scarce resource
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportFail.var.qml b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportFail.var.qml
new file mode 100644
index 0000000000..a1a3c1d66f
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportFail.var.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+import Qt.test 1.0
+import "scarceResourceCopyImportFail.var.js" as ScarceResourceCopyImportFailJs
+
+QtObject {
+ property var scarceResourceCopy: ScarceResourceCopyImportFailJs.importScarceResource()
+} \ No newline at end of file
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportFail.variant.js b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportFail.variant.js
new file mode 100644
index 0000000000..b59b5b1fa9
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportFail.variant.js
@@ -0,0 +1,19 @@
+.import Qt.test 1.0 as JsQtTest
+
+// In this case, the "retn" variable will be evaluated during import.
+// Since the importScarceResource() function depends on this variable,
+// because we DO NOT call "retn.preserve()", the scarce resource will
+// be released after the import completes but prior to evaluation of
+// any binding which calls "importScarceResource()".
+// Thus, "importScarceResource()" will return a released (invalid)
+// scarce resource.
+
+var component = Qt.createComponent("scarceResourceCopy.variant.qml");
+var scarceResourceElement = component.createObject(null);
+var scarceResourceProvider = scarceResourceElement.a;
+var retn = scarceResourceProvider.scarceResource;
+
+function importScarceResource() {
+ return retn; // should return a released (invalid) scarce resource
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportFail.variant.qml b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportFail.variant.qml
new file mode 100644
index 0000000000..8f6dcd6603
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportFail.variant.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+import Qt.test 1.0
+import "scarceResourceCopyImportFail.variant.js" as ScarceResourceCopyImportFailJs
+
+QtObject {
+ property variant scarceResourceCopy: ScarceResourceCopyImportFailJs.importScarceResource()
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportNoBinding.var.js b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportNoBinding.var.js
new file mode 100644
index 0000000000..130199f78a
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportNoBinding.var.js
@@ -0,0 +1,15 @@
+.import Qt.test 1.0 as JsQtTest
+
+// In this case, the "retn" variable will be evaluated during import.
+// Since the importScarceResource() function depends on this variable,
+// because we DO NOT call "retn.preserve()", the scarce resource will
+// be released after the import completes but prior to evaluation of
+// any binding which calls "importScarceResource()".
+// Thus, "importScarceResource()" will return a released (invalid)
+// scarce resource.
+
+var component = Qt.createComponent("scarceResourceCopyNoBinding.var.qml");
+var scarceResourceElement = component.createObject(null);
+var scarceResourceProvider = scarceResourceElement.a;
+var retn = scarceResourceProvider.scarceResource;
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportNoBinding.var.qml b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportNoBinding.var.qml
new file mode 100644
index 0000000000..5284b40cc8
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportNoBinding.var.qml
@@ -0,0 +1,12 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+// the following js import doesn't manually preserve or destroy any resources
+import "scarceResourceCopyImportNoBinding.var.js" as ScarceResourceCopyImportNoBindingJs
+
+QtObject {
+ // in this case, there is an import but no binding evaluated.
+ // nonetheless, any resources which are not preserved, should
+ // be automatically released by the engine.
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportNoBinding.variant.js b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportNoBinding.variant.js
new file mode 100644
index 0000000000..14a36a19ea
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportNoBinding.variant.js
@@ -0,0 +1,15 @@
+.import Qt.test 1.0 as JsQtTest
+
+// In this case, the "retn" variable will be evaluated during import.
+// Since the importScarceResource() function depends on this variable,
+// because we DO NOT call "retn.preserve()", the scarce resource will
+// be released after the import completes but prior to evaluation of
+// any binding which calls "importScarceResource()".
+// Thus, "importScarceResource()" will return a released (invalid)
+// scarce resource.
+
+var component = Qt.createComponent("scarceResourceCopyNoBinding.variant.qml");
+var scarceResourceElement = component.createObject(null);
+var scarceResourceProvider = scarceResourceElement.a;
+var retn = scarceResourceProvider.scarceResource;
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportNoBinding.variant.qml b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportNoBinding.variant.qml
new file mode 100644
index 0000000000..826cbe49fc
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyImportNoBinding.variant.qml
@@ -0,0 +1,12 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+// the following js import doesn't manually preserve or destroy any resources
+import "scarceResourceCopyImportNoBinding.variant.js" as ScarceResourceCopyImportNoBindingJs
+
+QtObject {
+ // in this case, there is an import but no binding evaluated.
+ // nonetheless, any resources which are not preserved, should
+ // be automatically released by the engine.
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyNoBinding.var.qml b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyNoBinding.var.qml
new file mode 100644
index 0000000000..4adef39980
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyNoBinding.var.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+QtObject {
+ // this component doesn't bind any property to a scarce
+ // resource from the scarce resource provider,
+ // so the binding evaluation resource cleanup
+ // codepath shouldn't be activated; so if the resources
+ // are released, it will be due to the import evaluation
+ // resource cleanup codepath being activated correctly.
+ property MyScarceResourceObject a;
+ a: MyScarceResourceObject { id: scarceResourceProvider }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyNoBinding.variant.qml b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyNoBinding.variant.qml
new file mode 100644
index 0000000000..4adef39980
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceCopyNoBinding.variant.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+QtObject {
+ // this component doesn't bind any property to a scarce
+ // resource from the scarce resource provider,
+ // so the binding evaluation resource cleanup
+ // codepath shouldn't be activated; so if the resources
+ // are released, it will be due to the import evaluation
+ // resource cleanup codepath being activated correctly.
+ property MyScarceResourceObject a;
+ a: MyScarceResourceObject { id: scarceResourceProvider }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceDestroyedCopy.var.qml b/tests/auto/qml/qqmlecmascript/data/scarceResourceDestroyedCopy.var.qml
new file mode 100644
index 0000000000..500f5d5bd7
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceDestroyedCopy.var.qml
@@ -0,0 +1,13 @@
+import QtQuick 2.0
+import Qt.test 1.0
+import "scarceResourceTest.var.js" as ScarceResourceProviderJs
+
+// In this case, following the evaluation of the binding,
+// the scarceResourceTest value should be an invalid variant,
+// since the scarce resource will have been released.
+
+QtObject {
+ property MyScarceResourceObject a;
+ a: MyScarceResourceObject { id: scarceResourceProvider }
+ property var scarceResourceCopy: ScarceResourceProviderJs.importReleasedScarceResource(scarceResourceProvider);
+} \ No newline at end of file
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceDestroyedCopy.variant.qml b/tests/auto/qml/qqmlecmascript/data/scarceResourceDestroyedCopy.variant.qml
new file mode 100644
index 0000000000..7a3b845247
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceDestroyedCopy.variant.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+import Qt.test 1.0
+import "scarceResourceTest.variant.js" as ScarceResourceProviderJs
+
+// In this case, following the evaluation of the binding,
+// the scarceResourceTest value should be an invalid variant,
+// since the scarce resource will have been released.
+
+QtObject {
+ property MyScarceResourceObject a;
+ a: MyScarceResourceObject { id: scarceResourceProvider }
+ property variant scarceResourceCopy: ScarceResourceProviderJs.importReleasedScarceResource(scarceResourceProvider);
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceFunction.var.qml b/tests/auto/qml/qqmlecmascript/data/scarceResourceFunction.var.qml
new file mode 100644
index 0000000000..23e4c8d15e
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceFunction.var.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+// Here we import a scarce resource directly.
+// The copy is only assigned when retrieveScarceResource()
+// is called, and so should be detached prior to that.
+// The copy should be released when releaseScarceResource()
+// is called, and so should be detached after that.
+
+QtObject {
+ id: root
+ property MyScarceResourceObject a: MyScarceResourceObject { id: scarceResourceProvider }
+ property var scarceResourceCopy;
+
+ function retrieveScarceResource() {
+ root.scarceResourceCopy = scarceResourceProvider.scarceResource;
+ }
+
+ function releaseScarceResource() {
+ root.scarceResourceCopy = null;
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceFunction.variant.qml b/tests/auto/qml/qqmlecmascript/data/scarceResourceFunction.variant.qml
new file mode 100644
index 0000000000..fe3707b5d3
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceFunction.variant.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+// Here we import a scarce resource directly.
+// The copy is only assigned when retrieveScarceResource()
+// is called, and so should be detached prior to that.
+// The copy should be released when releaseScarceResource()
+// is called, and so should be detached after that.
+
+QtObject {
+ id: root
+ property MyScarceResourceObject a: MyScarceResourceObject { id: scarceResourceProvider }
+ property variant scarceResourceCopy;
+
+ function retrieveScarceResource() {
+ root.scarceResourceCopy = scarceResourceProvider.scarceResource;
+ }
+
+ function releaseScarceResource() {
+ root.scarceResourceCopy = null;
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceFunctionFail.var.qml b/tests/auto/qml/qqmlecmascript/data/scarceResourceFunctionFail.var.qml
new file mode 100644
index 0000000000..9b4b1e6fd9
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceFunctionFail.var.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+// In this example, a common syntax error will only be "caught"
+// when the function is called via:
+// QQmlVMEMetaObject::metaCall->invokeMetaMethod()
+// We would like to ensure that a useful error message is printed.
+
+QtObject {
+ id: root
+ property MyScarceResourceObject a: MyScarceResourceObject { id: scarceResourceProvider }
+ property var scarceResourceCopy;
+ property string srp_name: a.toString();
+
+ function retrieveScarceResource() {
+ root.scarceResourceCopy = scarceResourceProvider.scarceResource(); // common syntax error, should throw exception
+ }
+
+ function releaseScarceResource() {
+ root.scarceResourceCopy = null;
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceFunctionFail.variant.qml b/tests/auto/qml/qqmlecmascript/data/scarceResourceFunctionFail.variant.qml
new file mode 100644
index 0000000000..57673de3f3
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceFunctionFail.variant.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+// In this example, a common syntax error will only be "caught"
+// when the function is called via:
+// QQmlVMEMetaObject::metaCall->invokeMetaMethod()
+// We would like to ensure that a useful error message is printed.
+
+QtObject {
+ id: root
+ property MyScarceResourceObject a: MyScarceResourceObject { id: scarceResourceProvider }
+ property variant scarceResourceCopy;
+ property string srp_name: a.toString();
+
+ function retrieveScarceResource() {
+ root.scarceResourceCopy = scarceResourceProvider.scarceResource(); // common syntax error, should throw exception
+ }
+
+ function releaseScarceResource() {
+ root.scarceResourceCopy = null;
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceMultipleDifferentNoBinding.var.js b/tests/auto/qml/qqmlecmascript/data/scarceResourceMultipleDifferentNoBinding.var.js
new file mode 100644
index 0000000000..217f693456
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceMultipleDifferentNoBinding.var.js
@@ -0,0 +1,14 @@
+.import Qt.test 1.0 as JsQtTest
+
+function importScarceResource() {
+ var component = Qt.createComponent("scarceResourceCopy.var.qml");
+ var scarceResourceElement = component.createObject(null);
+ var scarceResourceProvider = scarceResourceElement.a;
+ var retn = scarceResourceProvider.scarceResource;
+ retn.preserve();
+ return retn;
+}
+
+function releaseScarceResource(resource) {
+ resource.destroy();
+} \ No newline at end of file
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceMultipleDifferentNoBinding.var.qml b/tests/auto/qml/qqmlecmascript/data/scarceResourceMultipleDifferentNoBinding.var.qml
new file mode 100644
index 0000000000..205131661f
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceMultipleDifferentNoBinding.var.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+import Qt.test 1.0
+import "scarceResourceMultipleDifferentNoBinding.var.js" as ScarceResourcesMultipleDifferentNoBinding
+
+QtObject {
+ property var resourceOne
+ property var resourceTwo
+
+ Component.onCompleted: {
+ resourceOne = ScarceResourcesMultipleDifferentNoBinding.importScarceResource();
+ resourceTwo = ScarceResourcesMultipleDifferentNoBinding.importScarceResource();
+ ScarceResourcesMultipleDifferentNoBinding.releaseScarceResource(resourceTwo);
+ }
+} \ No newline at end of file
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceMultipleSameNoBinding.var.js b/tests/auto/qml/qqmlecmascript/data/scarceResourceMultipleSameNoBinding.var.js
new file mode 100644
index 0000000000..5b2494c8e6
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceMultipleSameNoBinding.var.js
@@ -0,0 +1,15 @@
+.import Qt.test 1.0 as JsQtTest
+
+var component = Qt.createComponent("scarceResourceCopy.var.qml");
+var scarceResourceElement = component.createObject(null);
+var scarceResourceProvider = scarceResourceElement.a;
+var retn = scarceResourceProvider.scarceResource;
+retn.preserve();
+
+function importScarceResource() {
+ return retn;
+}
+
+function releaseScarceResource(resource) {
+ resource.destroy();
+} \ No newline at end of file
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceMultipleSameNoBinding.var.qml b/tests/auto/qml/qqmlecmascript/data/scarceResourceMultipleSameNoBinding.var.qml
new file mode 100644
index 0000000000..e7f6d7868f
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceMultipleSameNoBinding.var.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+import Qt.test 1.0
+import "scarceResourceMultipleSameNoBinding.var.js" as ScarceResourcesMultipleSameNoBinding
+
+QtObject {
+ property var resourceOne
+ property var resourceTwo
+
+ Component.onCompleted: {
+ resourceOne = ScarceResourcesMultipleSameNoBinding.importScarceResource();
+ resourceTwo = ScarceResourcesMultipleSameNoBinding.importScarceResource();
+ ScarceResourcesMultipleSameNoBinding.releaseScarceResource(resourceTwo);
+ }
+} \ No newline at end of file
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceMultipleSameWithBinding.var.qml b/tests/auto/qml/qqmlecmascript/data/scarceResourceMultipleSameWithBinding.var.qml
new file mode 100644
index 0000000000..34cb97f39c
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceMultipleSameWithBinding.var.qml
@@ -0,0 +1,12 @@
+import QtQuick 2.0
+import Qt.test 1.0
+import "scarceResourceMultipleDifferentNoBinding.var.js" as ScarceResourcesMultipleDifferentNoBinding
+
+QtObject {
+ property var resourceOne: ScarceResourcesMultipleDifferentNoBinding.importScarceResource()
+ property var resourceTwo: resourceOne
+
+ Component.onCompleted: {
+ ScarceResourcesMultipleDifferentNoBinding.releaseScarceResource(resourceTwo);
+ }
+} \ No newline at end of file
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceObjectGc.var.qml b/tests/auto/qml/qqmlecmascript/data/scarceResourceObjectGc.var.qml
new file mode 100644
index 0000000000..7ec98e6619
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceObjectGc.var.qml
@@ -0,0 +1,30 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ id: testScarce
+
+ property var varProperty
+
+ property var canary: 4
+
+ // constructs an Item which contains a scarce resource.
+ function constructScarceObject() {
+ var retn = 1;
+ var component = Qt.createComponent("ScarceResourceVarComponent.qml");
+ if (component.status == Component.Ready) {
+ retn = component.createObject(null); // has JavaScript ownership
+ }
+ return retn;
+ }
+
+ function assignVarProperty() {
+ varProperty = constructScarceObject();
+ gc();
+ }
+
+ function deassignVarProperty() {
+ varProperty = 2; // causes the original object to be garbage collected.
+ gc(); // image should be detached; ep->sr should be empty!
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceSignal.var.qml b/tests/auto/qml/qqmlecmascript/data/scarceResourceSignal.var.qml
new file mode 100644
index 0000000000..0b30e88fa8
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceSignal.var.qml
@@ -0,0 +1,29 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+QtObject {
+ id: root
+
+ property MyScarceResourceObject a;
+ a: MyScarceResourceObject { id: scarceResourceProvider }
+
+ property ScarceResourceSignalComponentVar b;
+ b: ScarceResourceSignalComponentVar {
+ objectName: "srsc"
+
+ onTestSignal: {
+ // this signal will be invoked manually in the test.
+ // the scarce resource should be released automatically after evaluation
+ // and since we don't keep a copy of it, the pixmap will be detached.
+ width = (scarceResourceProvider.scarceResource,10)
+ }
+
+ onTestSignal2: {
+ // this signal will be invoked manually in the test.
+ // the scarce resource should be released automatically after evaluation
+ // but since we assign it to a property, the pixmap won't be detached.
+ scarceResourceCopy = scarceResourceProvider.scarceResource
+ }
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceSignal.variant.qml b/tests/auto/qml/qqmlecmascript/data/scarceResourceSignal.variant.qml
new file mode 100644
index 0000000000..1011c7e240
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceSignal.variant.qml
@@ -0,0 +1,29 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+QtObject {
+ id: root
+
+ property MyScarceResourceObject a;
+ a: MyScarceResourceObject { id: scarceResourceProvider }
+
+ property ScarceResourceSignalComponentVariant b;
+ b: ScarceResourceSignalComponentVariant {
+ objectName: "srsc"
+
+ onTestSignal: {
+ // this signal will be invoked manually in the test.
+ // the scarce resource should be released automatically after evaluation
+ // and since we don't keep a copy of it, the pixmap will be detached.
+ width = (scarceResourceProvider.scarceResource,10)
+ }
+
+ onTestSignal2: {
+ // this signal will be invoked manually in the test.
+ // the scarce resource should be released automatically after evaluation
+ // but since we assign it to a property, the pixmap won't be detached.
+ scarceResourceCopy = scarceResourceProvider.scarceResource
+ }
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceTest.var.js b/tests/auto/qml/qqmlecmascript/data/scarceResourceTest.var.js
new file mode 100644
index 0000000000..c904eb3564
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceTest.var.js
@@ -0,0 +1,48 @@
+.import Qt.test 1.0 as JsQtTest
+
+function importScarceResource(scarceResourceProvider) {
+ // the scarce resource should be automatically released
+ // after the binding is evaluated if preserve is not
+ // called.
+ return scarceResourceProvider.scarceResource;
+}
+
+function importPreservedScarceResource(scarceResourceProvider) {
+ // the scarce resource is manually preserved
+ // during the evaluation of the binding.
+ // it should not be released.
+ var scarceResource = scarceResourceProvider.scarceResource;
+ scarceResource.preserve();
+ return scarceResource;
+}
+
+function importReleasedScarceResource(scarceResourceProvider) {
+ // release the scarce resource during the
+ // evaluation of the binding. The returned
+ // variant will therefore be invalid.
+ var scarceResource = scarceResourceProvider.scarceResource;
+ scarceResource.destroy();
+ return scarceResource;
+}
+
+function importPreservedScarceResourceFromMultiple(scarceResourceProvider) {
+ // some scarce resources are manually preserved,
+ // some of them are manually destroyed,
+ // and some are automatically managed.
+ // We return a preserved resource
+ var sr1 = scarceResourceProvider.scarceResource; // preserved/destroyed.
+ sr1.preserve();
+ var sr2 = scarceResourceProvider.scarceResource; // preserved/destroyed
+ sr2.preserve();
+ var sr3 = scarceResourceProvider.scarceResource; // automatic.
+ var sr4 = scarceResourceProvider.scarceResource; // automatic and returned.
+ var sr5 = scarceResourceProvider.scarceResource; // destroyed
+ sr5.destroy();
+ sr2.destroy();
+ var sr6 = scarceResourceProvider.scarceResource; // destroyed
+ var sr7 = scarceResourceProvider.scarceResource; // automatic
+ sr1.destroy();
+ sr6.destroy();
+ return sr4;
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceTest.var.qml b/tests/auto/qml/qqmlecmascript/data/scarceResourceTest.var.qml
new file mode 100644
index 0000000000..1d4e67055e
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceTest.var.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+// Here we import a scarce resource directly, and use it in a binding.
+// It is not preserved or released manually, so it should be
+// automatically released once evaluation of the binding
+// is complete.
+
+QtObject {
+ property MyScarceResourceObject a;
+ a: MyScarceResourceObject { id: scarceResourceProvider }
+ property int scarceResourceTest: scarceResourceProvider.scarceResource,100 // return 100, but include the scarceResource in the binding to be evaluated.
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceTest.variant.js b/tests/auto/qml/qqmlecmascript/data/scarceResourceTest.variant.js
new file mode 100644
index 0000000000..c904eb3564
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceTest.variant.js
@@ -0,0 +1,48 @@
+.import Qt.test 1.0 as JsQtTest
+
+function importScarceResource(scarceResourceProvider) {
+ // the scarce resource should be automatically released
+ // after the binding is evaluated if preserve is not
+ // called.
+ return scarceResourceProvider.scarceResource;
+}
+
+function importPreservedScarceResource(scarceResourceProvider) {
+ // the scarce resource is manually preserved
+ // during the evaluation of the binding.
+ // it should not be released.
+ var scarceResource = scarceResourceProvider.scarceResource;
+ scarceResource.preserve();
+ return scarceResource;
+}
+
+function importReleasedScarceResource(scarceResourceProvider) {
+ // release the scarce resource during the
+ // evaluation of the binding. The returned
+ // variant will therefore be invalid.
+ var scarceResource = scarceResourceProvider.scarceResource;
+ scarceResource.destroy();
+ return scarceResource;
+}
+
+function importPreservedScarceResourceFromMultiple(scarceResourceProvider) {
+ // some scarce resources are manually preserved,
+ // some of them are manually destroyed,
+ // and some are automatically managed.
+ // We return a preserved resource
+ var sr1 = scarceResourceProvider.scarceResource; // preserved/destroyed.
+ sr1.preserve();
+ var sr2 = scarceResourceProvider.scarceResource; // preserved/destroyed
+ sr2.preserve();
+ var sr3 = scarceResourceProvider.scarceResource; // automatic.
+ var sr4 = scarceResourceProvider.scarceResource; // automatic and returned.
+ var sr5 = scarceResourceProvider.scarceResource; // destroyed
+ sr5.destroy();
+ sr2.destroy();
+ var sr6 = scarceResourceProvider.scarceResource; // destroyed
+ var sr7 = scarceResourceProvider.scarceResource; // automatic
+ sr1.destroy();
+ sr6.destroy();
+ return sr4;
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceTest.variant.qml b/tests/auto/qml/qqmlecmascript/data/scarceResourceTest.variant.qml
new file mode 100644
index 0000000000..1d4e67055e
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceTest.variant.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+// Here we import a scarce resource directly, and use it in a binding.
+// It is not preserved or released manually, so it should be
+// automatically released once evaluation of the binding
+// is complete.
+
+QtObject {
+ property MyScarceResourceObject a;
+ a: MyScarceResourceObject { id: scarceResourceProvider }
+ property int scarceResourceTest: scarceResourceProvider.scarceResource,100 // return 100, but include the scarceResource in the binding to be evaluated.
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceTestMultiple.var.qml b/tests/auto/qml/qqmlecmascript/data/scarceResourceTestMultiple.var.qml
new file mode 100644
index 0000000000..5e6c2d97f9
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceTestMultiple.var.qml
@@ -0,0 +1,16 @@
+import QtQuick 2.0
+import Qt.test 1.0
+import "scarceResourceTest.var.js" as ScarceResourceProviderJs
+
+// In this case, multiple scarce resource are explicity preserved
+// and then explicitly destroyed, while others are automatically
+// managed. Since none are manually preserved without subsequently
+// being destroyed, after the evaluation of the binding the
+// scarce resource should be detached.
+
+QtObject {
+ property MyScarceResourceObject a;
+ a: MyScarceResourceObject { id: scarceResourceProvider }
+ property int scarceResourceTest: ScarceResourceProviderJs.importPreservedScarceResourceFromMultiple(scarceResourceProvider), 100
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceTestMultiple.variant.qml b/tests/auto/qml/qqmlecmascript/data/scarceResourceTestMultiple.variant.qml
new file mode 100644
index 0000000000..2970bcb26c
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceTestMultiple.variant.qml
@@ -0,0 +1,15 @@
+import QtQuick 2.0
+import Qt.test 1.0
+import "scarceResourceTest.variant.js" as ScarceResourceProviderJs
+
+// In this case, multiple scarce resource are explicity preserved
+// and then explicitly destroyed, while others are automatically
+// managed. Since none are manually preserved without subsequently
+// being destroyed, after the evaluation of the binding the
+// scarce resource should be detached.
+
+QtObject {
+ property MyScarceResourceObject a;
+ a: MyScarceResourceObject { id: scarceResourceProvider }
+ property int scarceResourceTest: ScarceResourceProviderJs.importPreservedScarceResourceFromMultiple(scarceResourceProvider), 100
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceTestPreserve.var.qml b/tests/auto/qml/qqmlecmascript/data/scarceResourceTestPreserve.var.qml
new file mode 100644
index 0000000000..9e9495c0fa
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceTestPreserve.var.qml
@@ -0,0 +1,15 @@
+import QtQuick 2.0
+import Qt.test 1.0
+import "scarceResourceTest.var.js" as ScarceResourceProviderJs
+
+// In this case, the scarce resource is explicity preserved.
+// It should not be automatically released after the evaluation
+// of the binding is complete, but instead will be kept in
+// memory until the JS garbage collector runs.
+
+QtObject {
+ property MyScarceResourceObject a;
+ a: MyScarceResourceObject { id: scarceResourceProvider }
+ property int scarceResourceTest: ScarceResourceProviderJs.importPreservedScarceResource(scarceResourceProvider),100 // return 100, but the resource should be preserved.
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scarceResourceTestPreserve.variant.qml b/tests/auto/qml/qqmlecmascript/data/scarceResourceTestPreserve.variant.qml
new file mode 100644
index 0000000000..022067beca
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scarceResourceTestPreserve.variant.qml
@@ -0,0 +1,15 @@
+import QtQuick 2.0
+import Qt.test 1.0
+import "scarceResourceTest.variant.js" as ScarceResourceProviderJs
+
+// In this case, the scarce resource is explicity preserved.
+// It should not be automatically released after the evaluation
+// of the binding is complete, but instead will be kept in
+// memory until the JS garbage collector runs.
+
+QtObject {
+ property MyScarceResourceObject a;
+ a: MyScarceResourceObject { id: scarceResourceProvider }
+ property int scarceResourceTest: ScarceResourceProviderJs.importPreservedScarceResource(scarceResourceProvider),100 // return 100, but the resource should be preserved.
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scope.2.qml b/tests/auto/qml/qqmlecmascript/data/scope.2.qml
new file mode 100644
index 0000000000..fe1c4c7931
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scope.2.qml
@@ -0,0 +1,40 @@
+import QtQuick 2.0
+
+Item {
+ property int a: 0
+ property int b: 14
+
+ function b() { return 11; }
+ function c() { return 33; }
+
+ QtObject {
+ id: a
+ property int value: 19
+ }
+
+ QtObject {
+ id: c
+ property int value: 24
+ }
+
+ QtObject {
+ id: nested
+ property int a: 1
+ property int test: a.value
+ property int test2: b
+ property int test3: c.value
+ }
+
+
+ // id takes precedence over local, and root properties
+ property int test1: a.value
+ property alias test2: nested.test
+
+ // properties takes precedence over local, and root methods
+ property int test3: b
+ property alias test4: nested.test2
+
+ // id takes precedence over methods
+ property int test5: c.value
+ property alias test6: nested.test3
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/scope.3.qml b/tests/auto/qml/qqmlecmascript/data/scope.3.qml
new file mode 100644
index 0000000000..9add81809c
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scope.3.qml
@@ -0,0 +1,13 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+MyQmlObject {
+ id: root
+
+ property int foo: 12
+
+ property bool test1: foo == 12
+ property bool test2: console != 11
+ property bool test3: root.console == 11
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scope.4.qml b/tests/auto/qml/qqmlecmascript/data/scope.4.qml
new file mode 100644
index 0000000000..d65b6e7c7c
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scope.4.qml
@@ -0,0 +1,12 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ id: a
+ property int b: 9
+
+ property int test
+ property string test2
+
+ // Should resolve to signal arguments, not to other elements in the file
+ onArgumentSignal: { test = a; test2 = b; }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/scope.5.qml b/tests/auto/qml/qqmlecmascript/data/scope.5.qml
new file mode 100644
index 0000000000..6dbcbe2a40
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scope.5.qml
@@ -0,0 +1,27 @@
+import QtQuick 2.0
+
+Item {
+ property bool test1: false;
+ property bool test2: false;
+
+ property int a: 10
+
+ Item {
+ id: nested
+ property int a: 11
+
+ function mynestedfunction() {
+ return a;
+ }
+ }
+
+ function myouterfunction() {
+ return a;
+ }
+
+ Component.onCompleted: {
+ test1 = (myouterfunction() == 10);
+ test2 = (nested.mynestedfunction() == 11);
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scope.6.qml b/tests/auto/qml/qqmlecmascript/data/scope.6.qml
new file mode 100644
index 0000000000..5897b533d7
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scope.6.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.0
+
+Item {
+ id: me
+ property bool test: nested.runtest(me);
+
+ Scope6Nested {
+ id: nested
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/scope.qml b/tests/auto/qml/qqmlecmascript/data/scope.qml
new file mode 100644
index 0000000000..a00352b684
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scope.qml
@@ -0,0 +1,44 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+
+ property int a: 1
+ property int binding: a
+ property string binding2: a + "Test"
+ property int binding3: myFunction()
+ property int binding4: nestedObject.myNestedFunction()
+
+ function myFunction() {
+ return a;
+ }
+
+ Item {
+ id: nestedObject
+
+ function myNestedFunction() {
+ return a;
+ }
+
+ property int a: 2
+ property int binding: a
+ property string binding2: a + "Test"
+ property int binding3: myFunction()
+ property int binding4: myNestedFunction()
+ }
+
+ ScopeObject {
+ id: compObject
+ }
+
+ property alias test1: root.binding
+ property alias test2: nestedObject.binding
+ property alias test3: root.binding2
+ property alias test4: nestedObject.binding2
+ property alias test5: root.binding3
+ property alias test6: nestedObject.binding3
+ property alias test7: root.binding4
+ property alias test8: nestedObject.binding4
+ property alias test9: compObject.binding
+ property alias test10: compObject.binding2
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/scriptConnect.1.js b/tests/auto/qml/qqmlecmascript/data/scriptConnect.1.js
new file mode 100644
index 0000000000..54284fea47
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scriptConnect.1.js
@@ -0,0 +1,4 @@
+function testFunction() {
+ test = true;
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scriptConnect.1.qml b/tests/auto/qml/qqmlecmascript/data/scriptConnect.1.qml
new file mode 100644
index 0000000000..ace473756e
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scriptConnect.1.qml
@@ -0,0 +1,10 @@
+import Qt.test 1.0
+import QtQuick 2.0
+import "scriptConnect.1.js" as Script
+MyQmlObject {
+ property bool test: false
+
+ id: root
+
+ Component.onCompleted: root.argumentSignal.connect(Script.testFunction);
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/scriptConnect.2.js b/tests/auto/qml/qqmlecmascript/data/scriptConnect.2.js
new file mode 100644
index 0000000000..595c778aa7
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scriptConnect.2.js
@@ -0,0 +1,5 @@
+function testFunction() {
+ if (this.b == 12)
+ test = true;
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scriptConnect.2.qml b/tests/auto/qml/qqmlecmascript/data/scriptConnect.2.qml
new file mode 100644
index 0000000000..cdf2d6ad98
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scriptConnect.2.qml
@@ -0,0 +1,16 @@
+import Qt.test 1.0
+import QtQuick 2.0
+import "scriptConnect.2.js" as Script
+
+MyQmlObject {
+ property bool test: false
+
+ id: root
+
+ Component.onCompleted: {
+ var a = new Object;
+ a.b = 12;
+ root.argumentSignal.connect(a, Script.testFunction);
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scriptConnect.3.qml b/tests/auto/qml/qqmlecmascript/data/scriptConnect.3.qml
new file mode 100644
index 0000000000..b0e40565c0
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scriptConnect.3.qml
@@ -0,0 +1,15 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+MyQmlObject {
+ property bool test: false
+
+ id: root
+
+ function testFunction() {
+ test = true;
+ }
+
+ Component.onCompleted: root.argumentSignal.connect(testFunction);
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scriptConnect.4.qml b/tests/auto/qml/qqmlecmascript/data/scriptConnect.4.qml
new file mode 100644
index 0000000000..ef5331c94a
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scriptConnect.4.qml
@@ -0,0 +1,12 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+MyQmlObject {
+ property bool test: false
+
+ id: root
+
+ Component.onCompleted: root.argumentSignal.connect(methodNoArgs);
+}
+
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scriptConnect.5.qml b/tests/auto/qml/qqmlecmascript/data/scriptConnect.5.qml
new file mode 100644
index 0000000000..8dcacbcbb7
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scriptConnect.5.qml
@@ -0,0 +1,11 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+MyQmlObject {
+ property bool test: false
+
+ id: root
+
+ Component.onCompleted: root.argumentSignal.connect(root, methodNoArgs);
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scriptConnect.6.js b/tests/auto/qml/qqmlecmascript/data/scriptConnect.6.js
new file mode 100644
index 0000000000..71bdd088a2
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scriptConnect.6.js
@@ -0,0 +1,3 @@
+function testFunction() {
+ test++;
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/scriptConnect.6.qml b/tests/auto/qml/qqmlecmascript/data/scriptConnect.6.qml
new file mode 100644
index 0000000000..06b6f0fa62
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scriptConnect.6.qml
@@ -0,0 +1,15 @@
+import Qt.test 1.0
+import QtQuick 2.0
+import "scriptConnect.6.js" as Script
+
+MyQmlObject {
+ property int test: 0
+
+ id: root
+
+ Component.onCompleted: {
+ root.argumentSignal.connect(Script.testFunction);
+ root.argumentSignal.connect(Script.testFunction);
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scriptDisconnect.1.js b/tests/auto/qml/qqmlecmascript/data/scriptDisconnect.1.js
new file mode 100644
index 0000000000..407426fcd1
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scriptDisconnect.1.js
@@ -0,0 +1,6 @@
+function testFunction() {
+ test++;
+}
+
+function otherFunction() {
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/scriptDisconnect.1.qml b/tests/auto/qml/qqmlecmascript/data/scriptDisconnect.1.qml
new file mode 100644
index 0000000000..e546ee44d8
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scriptDisconnect.1.qml
@@ -0,0 +1,13 @@
+import Qt.test 1.0
+import QtQuick 2.0
+import "scriptDisconnect.1.js" as Script
+
+MyQmlObject {
+ property int test: 0
+
+ id: root
+
+ Component.onCompleted: root.argumentSignal.connect(Script.testFunction);
+
+ onBasicSignal: root.argumentSignal.disconnect(Script.testFunction);
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/scriptDisconnect.2.qml b/tests/auto/qml/qqmlecmascript/data/scriptDisconnect.2.qml
new file mode 100644
index 0000000000..e70cd8b900
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scriptDisconnect.2.qml
@@ -0,0 +1,14 @@
+import Qt.test 1.0
+import QtQuick 2.0
+import "scriptDisconnect.1.js" as Script
+
+MyQmlObject {
+ property int test: 0
+
+ id: root
+
+ Component.onCompleted: root.argumentSignal.connect(root, Script.testFunction);
+
+ onBasicSignal: root.argumentSignal.disconnect(root, Script.testFunction);
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scriptDisconnect.3.qml b/tests/auto/qml/qqmlecmascript/data/scriptDisconnect.3.qml
new file mode 100644
index 0000000000..6f47776ea5
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scriptDisconnect.3.qml
@@ -0,0 +1,14 @@
+import Qt.test 1.0
+import QtQuick 2.0
+import "scriptDisconnect.1.js" as Script
+
+MyQmlObject {
+ property int test: 0
+
+ id: root
+
+ Component.onCompleted: root.argumentSignal.connect(root, Script.testFunction);
+
+ onBasicSignal: root.argumentSignal.disconnect(Script.testFunction);
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/scriptDisconnect.4.qml b/tests/auto/qml/qqmlecmascript/data/scriptDisconnect.4.qml
new file mode 100644
index 0000000000..b3887545fb
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scriptDisconnect.4.qml
@@ -0,0 +1,13 @@
+import Qt.test 1.0
+import QtQuick 2.0
+import "scriptDisconnect.1.js" as Script
+
+MyQmlObject {
+ property int test: 0
+
+ id: root
+
+ Component.onCompleted: root.argumentSignal.connect(Script.testFunction);
+
+ onBasicSignal: root.argumentSignal.disconnect(Script.otherFunction);
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/scriptErrors.js b/tests/auto/qml/qqmlecmascript/data/scriptErrors.js
new file mode 100644
index 0000000000..d22f623edb
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scriptErrors.js
@@ -0,0 +1,4 @@
+// Comment
+a = 10
+
+function getValue() { a = 10; return 0; }
diff --git a/tests/auto/qml/qqmlecmascript/data/scriptErrors.qml b/tests/auto/qml/qqmlecmascript/data/scriptErrors.qml
new file mode 100644
index 0000000000..4998f63929
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/scriptErrors.qml
@@ -0,0 +1,18 @@
+import Qt.test 1.0
+import "scriptErrors.js" as Script
+
+MyQmlObject {
+ property int t: a.value
+ property int w: Script.getValue();
+ property int d: undefined
+ ? 0 // multi-line binding
+ : 1
+ property int x: undefined
+ property int y: (a.value, undefinedObject)
+
+ onBasicSignal: { console.log(a.value); }
+ id: myObj
+ onAnotherBasicSignal: myObj.trueProperty = false;
+ onThirdBasicSignal: myObj.fakeProperty = "";
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/selfDeletingBinding.2.qml b/tests/auto/qml/qqmlecmascript/data/selfDeletingBinding.2.qml
new file mode 100644
index 0000000000..58cf8051f0
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/selfDeletingBinding.2.qml
@@ -0,0 +1,17 @@
+import Qt.test 1.0
+
+MyQmlContainer {
+ property bool triggerDelete: false
+
+ children: [
+ MyQmlObject {
+ // Will trigger deletion on binding assignment
+ deleteOnSet: Math.max(0, 1)
+ },
+
+ MyQmlObject {
+ // Will trigger deletion on binding assignment, but after component creation
+ deleteOnSet: if (triggerDelete) 1; else 0;
+ }
+ ]
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/selfDeletingBinding.qml b/tests/auto/qml/qqmlecmascript/data/selfDeletingBinding.qml
new file mode 100644
index 0000000000..074851a67b
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/selfDeletingBinding.qml
@@ -0,0 +1,18 @@
+import Qt.test 1.0
+
+MyQmlContainer {
+ property bool triggerDelete: false
+
+ children: [
+ MyQmlObject {
+ // Will trigger deletion during binding evaluation
+ stringProperty: {deleteMe(), "Hello"}
+ },
+
+ MyQmlObject {
+ // Will trigger deletion during binding evaluation, but after component creation
+ stringProperty: if (triggerDelete) { deleteMe(), "Hello" } else { "World" }
+ }
+
+ ]
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/sequenceConversion.array.qml b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.array.qml
new file mode 100644
index 0000000000..52abda1e55
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.array.qml
@@ -0,0 +1,193 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ id: root
+ objectName: "root"
+
+ MySequenceConversionObject {
+ id: msco
+ objectName: "msco"
+ }
+
+ property bool success: false
+
+ property variant intList
+ property variant qrealList
+ property variant boolList
+ property variant stringList
+
+ function indexedAccess() {
+ intList = msco.intListProperty;
+ var jsIntList = msco.intListProperty;
+ qrealList = msco.qrealListProperty;
+ var jsQrealList = msco.qrealListProperty;
+ boolList = msco.boolListProperty;
+ var jsBoolList = msco.boolListProperty;
+ stringList = msco.stringListProperty;
+ var jsStringList = msco.stringListProperty;
+
+ // Three cases: direct property modification, variant copy modification, js var reference modification.
+ // Only the first and third should "write back" to the original QObject Q_PROPERTY; the second one
+ // should have no effect whatsoever to maintain "property variant" semantics (see e.g., valuetype).
+ success = true;
+
+ msco.intListProperty[1] = 33;
+ if (msco.intListProperty[1] != 33) success = false; // ensure write back
+ intList[1] = 44;
+ if (intList[1] == 44) success = false; // ensure no effect
+ jsIntList[1] = 55;
+ if (jsIntList[1] != 55
+ || jsIntList[1] != msco.intListProperty[1]) success = false; // ensure write back
+
+ msco.qrealListProperty[1] = 33.3;
+ if (msco.qrealListProperty[1] != 33.3) success = false; // ensure write back
+ qrealList[1] = 44.4;
+ if (qrealList[1] == 44.4) success = false; // ensure no effect
+ jsQrealList[1] = 55.5;
+ if (jsQrealList[1] != 55.5
+ || jsQrealList[1] != msco.qrealListProperty[1]) success = false; // ensure write back
+
+ msco.boolListProperty[1] = true;
+ if (msco.boolListProperty[1] != true) success = false; // ensure write back
+ boolList[1] = true;
+ if (boolList[1] != false) success = false; // ensure no effect
+ jsBoolList[1] = false;
+ if (jsBoolList[1] != false
+ || jsBoolList[1] != msco.boolListProperty[1]) success = false; // ensure write back
+
+ msco.stringListProperty[1] = "changed";
+ if (msco.stringListProperty[1] != "changed") success = false; // ensure write back
+ stringList[1] = "changed";
+ if (stringList[1] != "second") success = false; // ensure no effect
+ jsStringList[1] = "different";
+ if (jsStringList[1] != "different"
+ || jsStringList[1] != msco.stringListProperty[1]) success = false; // ensure write back
+ }
+
+ function arrayOperations() {
+ success = true;
+ var expected = 0;
+ var expectedStr = "";
+
+ // ecma262r3 defines array as implementing Length and Put. Test put here.
+ msco.intListProperty.asdf = 5; // shouldn't work, only indexes are valid names.
+ if (msco.intListProperty.asdf == 5) success = false;
+ msco.intListProperty[3] = 38; // should work.
+ if (msco.intListProperty[3] != 38) success = false;
+ msco.intListProperty[199] = 200; // should work, and should set length to 200.
+ if (msco.intListProperty[199] != 200) success = false;
+ if (msco.intListProperty.length != 200) success = false;
+
+ // test indexed deleter
+ msco.intListProperty = [ 1, 2, 3, 4, 5 ];
+ delete msco.intListProperty[-1];
+ expected = [ 1, 2, 3, 4, 5 ];
+ if (msco.intListProperty.toString() != expected.toString()) success = false;
+ delete msco.intListProperty[0];
+ expected = [ 0, 2, 3, 4, 5 ];
+ if (msco.intListProperty.toString() != expected.toString()) success = false;
+ delete msco.intListProperty[2];
+ expected = [ 0, 2, 0, 4, 5 ];
+ if (msco.intListProperty.toString() != expected.toString()) success = false;
+ delete msco.intListProperty[7];
+ expected = [ 0, 2, 0, 4, 5 ];
+ if (msco.intListProperty.toString() != expected.toString()) success = false;
+
+ // other operations are defined on the array prototype; see if they work.
+
+ // splice
+ msco.intListProperty = [ 0, 1, 2, 3, 4, 5, 6, 7 ];
+ msco.intListProperty.splice(1,3, 33, 44, 55, 66);
+ expected = [ 0, 33, 44, 55, 66, 4, 5, 6, 7 ];
+ if (msco.intListProperty.toString() != expected.toString()) success = false;
+ msco.intListProperty = [ 0, 1, 2, 3, 4, 5, 6, 7 ];
+ msco.intListProperty.splice(1, 3);
+ expected = [ 0, 4, 5, 6, 7 ];
+ if (msco.intListProperty.toString() != expected.toString()) success = false;
+
+ msco.qrealListProperty = [ 0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1 ];
+ msco.qrealListProperty.splice(1,3, 33.33, 44.44, 55.55, 66.66);
+ expected = [ 0.1, 33.33, 44.44, 55.55, 66.66, 4.1, 5.1, 6.1, 7.1 ];
+ if (msco.qrealListProperty.toString() != expected.toString()) success = false;
+ msco.qrealListProperty = [ 0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1 ];
+ msco.qrealListProperty.splice(1,3);
+ expected = [ 0.1, 4.1, 5.1, 6.1, 7.1 ];
+ if (msco.qrealListProperty.toString() != expected.toString()) success = false;
+
+ msco.boolListProperty = [ false, true, true, false, false, true, false, true ];
+ msco.boolListProperty.splice(1,3, false, true, false, false);
+ expected = [ false, false, true, false, false, false, true, false, true ];
+ if (msco.boolListProperty.toString() != expected.toString()) success = false;
+ msco.boolListProperty = [ false, true, true, false, false, true, false, true ];
+ msco.boolListProperty.splice(1,3);
+ expected = [ false, false, true, false, true ];
+ if (msco.boolListProperty.toString() != expected.toString()) success = false;
+
+ msco.stringListProperty = [ "one", "two", "three", "four", "five", "six", "seven", "eight" ];
+ msco.stringListProperty.splice(1,3, "nine", "ten", "eleven", "twelve");
+ expected = [ "one", "nine", "ten", "eleven", "twelve", "five", "six", "seven", "eight" ];
+ if (msco.stringListProperty.toString() != expected.toString()) success = false;
+ msco.stringListProperty = [ "one", "two", "three", "four", "five", "six", "seven", "eight" ];
+ msco.stringListProperty.splice(0,3);
+ expected = [ "four", "five", "six", "seven", "eight" ];
+ if (msco.stringListProperty.toString() != expected.toString()) success = false;
+
+ // pop
+ msco.intListProperty = [ 0, 1, 2, 3, 4, 5, 6, 7 ];
+ var poppedVal = msco.intListProperty.pop();
+ expected = [ 0, 1, 2, 3, 4, 5, 6 ];
+ if (msco.intListProperty.toString() != expected.toString()) success = false;
+ expected = 7;
+ if (poppedVal != expected) success = false;
+ }
+
+ property variant variantList: [ 1, 2, 3, 4, 5 ];
+ property variant variantList2: [ 1, 2, 3, 4, 5 ];
+ function testEqualitySemantics() {
+ // ensure equality semantics match JS array equality semantics
+ success = true;
+
+ msco.intListProperty = [ 1, 2, 3, 4, 5 ];
+ msco.intListProperty2 = [ 1, 2, 3, 4, 5 ];
+ var jsIntList = [ 1, 2, 3, 4, 5 ];
+ var jsIntList2 = [ 1, 2, 3, 4, 5 ];
+
+ if (jsIntList != jsIntList) success = false;
+ if (jsIntList == jsIntList2) success = false;
+ if (jsIntList == msco.intListProperty) success = false;
+ if (jsIntList == variantList) success = false;
+
+ if (msco.intListProperty != msco.intListProperty) success = false;
+ if (msco.intListProperty == msco.intListProperty2) success = false;
+ if (msco.intListProperty == jsIntList) success = false;
+ if (msco.intListProperty == variantList) success = false;
+
+ if (variantList == variantList) return false;
+ if (variantList == variantList2) return false;
+ if (variantList == msco.intListProperty) return false;
+ if (variantList == jsIntList) return false;
+
+ if ((jsIntList == jsIntList2) != (jsIntList == msco.intListProperty)) success = false;
+ if ((jsIntList == jsIntList2) != (msco.intListProperty == msco.intListProperty2)) success = false;
+ if ((jsIntList == jsIntList) != (msco.intListProperty == msco.intListProperty)) success = false;
+ if ((jsIntList == variantList) != (msco.intListProperty == variantList)) success = false;
+ if ((variantList == jsIntList) != (variantList == msco.intListProperty)) success = false;
+ if ((msco.intListProperty == variantList) != (variantList == msco.intListProperty)) success = false;
+ }
+
+ property bool referenceDeletion: false
+ function testReferenceDeletion() {
+ referenceDeletion = true;
+ var testObj = msco.generateTestObject();
+ testObj.intListProperty = [1, 2, 3, 4, 5];
+ var testSequence = testObj.intListProperty;
+ var prevString = testSequence.toString();
+ var prevValueOf = testSequence.valueOf();
+ var prevLength = testSequence.length;
+ msco.deleteTestObject(testObj); // delete referenced object.
+ if (testSequence.toString() == prevString) referenceDeletion = false;
+ if (testSequence.valueOf() == prevValueOf) referenceDeletion = false;
+ if (testSequence.length == prevLength) referenceDeletion = false;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/sequenceConversion.bindings.error.qml b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.bindings.error.qml
new file mode 100644
index 0000000000..9c87dd293e
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.bindings.error.qml
@@ -0,0 +1,19 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ id: root
+ objectName: "root"
+
+ MySequenceConversionObject {
+ id: msco
+ objectName: "msco"
+ intListProperty: [ 1, 2, 3, 6, 7 ]
+ }
+
+ MySequenceConversionObject {
+ id: mscoTwo
+ objectName: "mscoTwo"
+ boolListProperty: msco.intListProperty
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/sequenceConversion.bindings.qml b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.bindings.qml
new file mode 100644
index 0000000000..8d83e9f9f5
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.bindings.qml
@@ -0,0 +1,28 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ id: root
+ objectName: "root"
+
+ MySequenceConversionObject {
+ id: msco
+ objectName: "msco"
+ intListProperty: [ 1, 2, 3, 6, 7 ]
+ }
+
+ MySequenceConversionObject {
+ id: mscoTwo
+ objectName: "mscoTwo"
+ intListProperty: msco.intListProperty
+ }
+
+ property variant boundSequence: msco.intListProperty
+ property int boundElement: msco.intListProperty[3]
+ property variant boundSequenceTwo: mscoTwo.intListProperty
+
+ Component.onCompleted: {
+ msco.intListProperty[3] = 12;
+ mscoTwo.intListProperty[4] = 14;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/sequenceConversion.copy.qml b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.copy.qml
new file mode 100644
index 0000000000..f6614dad0c
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.copy.qml
@@ -0,0 +1,160 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ id: root
+ objectName: "root"
+
+ MySequenceConversionObject {
+ id: msco
+ objectName: "msco"
+ }
+
+ property bool success: true
+
+ property variant intList
+ property variant qrealList
+ property variant boolList
+ property variant stringList
+ property variant urlList
+ property variant qstringList
+
+ // this test ensures that the "copy resource" codepaths work
+ function testCopySequences() {
+ success = true;
+
+ // create "copy resource" sequences
+ var jsIntList = msco.generateIntSequence();
+ var jsQrealList = msco.generateQrealSequence();
+ var jsBoolList = msco.generateBoolSequence();
+ var jsStringList = msco.generateStringSequence();
+ var jsUrlList = msco.generateUrlSequence();
+ var jsQStringList = msco.generateQStringSequence();
+
+ if (jsIntList.toString() != [1, 2, 3].toString())
+ success = false;
+ if (jsQrealList.toString() != [1.1, 2.2, 3.3].toString())
+ success = false;
+ if (jsBoolList.toString() != [true, false, true].toString())
+ success = false;
+ if (jsStringList.toString() != ["one", "two", "three"].toString())
+ success = false;
+ if (jsUrlList.toString() != ["http://www.example1.com", "http://www.example2.com", "http://www.example3.com"].toString())
+ success = false;
+ if (jsQStringList.toString() != ["one", "two", "three"].toString())
+ success = false;
+
+ // copy the sequence; should result in a new copy
+ intList = jsIntList;
+ qrealList = jsQrealList;
+ boolList = jsBoolList;
+ stringList = jsStringList;
+ urlList = jsUrlList;
+ qstringList = jsQStringList;
+
+ // these operations shouldn't modify either variables - because
+ // we don't handle writing to the intermediate variant at list[index]
+ // for variant properties.
+ intList[1] = 8;
+ qrealList[1] = 8.8;
+ boolList[1] = true;
+ stringList[1] = "eight";
+ urlList[1] = "http://www.example8.com";
+ qstringList[1] = "eight";
+
+ if (jsIntList[1] == 8)
+ success = false;
+ if (jsQrealList[1] == 8.8)
+ success = false;
+ if (jsBoolList[1] == true)
+ success = false;
+ if (jsStringList[1] == "eight")
+ success = false;
+ if (jsUrlList[1] == "http://www.example8.com")
+ success = false;
+ if (jsQStringList[1] == "eight")
+ success = false;
+
+ // assign a "copy resource" sequence to a QObject Q_PROPERTY
+ msco.intListProperty = intList;
+ msco.qrealListProperty = qrealList;
+ msco.boolListProperty = boolList;
+ msco.stringListProperty = stringList;
+ msco.urlListProperty = urlList;
+ msco.qstringListProperty = qstringList;
+
+ if (msco.intListProperty.toString() != [1, 2, 3].toString())
+ success = false;
+ if (msco.qrealListProperty.toString() != [1.1, 2.2, 3.3].toString())
+ success = false;
+ if (msco.boolListProperty.toString() != [true, false, true].toString())
+ success = false;
+ if (msco.stringListProperty.toString() != ["one", "two", "three"].toString())
+ success = false;
+ if (msco.urlListProperty.toString() != ["http://www.example1.com", "http://www.example2.com", "http://www.example3.com"].toString())
+ success = false;
+ if (msco.qstringListProperty.toString() != ["one", "two", "three"].toString())
+ success = false;
+
+ // now modify the QObject Q_PROPERTY (reference resource) sequences - shouldn't modify the copy resource sequences.
+ msco.intListProperty[2] = 9;
+ msco.qrealListProperty[2] = 9.9;
+ msco.boolListProperty[2] = false;
+ msco.stringListProperty[2] = "nine";
+ msco.urlListProperty[2] = "http://www.example9.com";
+ msco.qstringListProperty[2] = "nine";
+
+ if (intList[2] == 9)
+ success = false;
+ if (qrealList[2] == 9.9)
+ success = false;
+ if (boolList[2] == false)
+ success = false;
+ if (stringList[2] == "nine")
+ success = false;
+ if (urlList[2] == "http://www.example9.com")
+ success = false;
+ if (qstringList[2] == "nine")
+ success = false;
+ }
+
+ property int intVal
+ property real qrealVal
+ property bool boolVal
+ property string stringVal
+
+ // this test ensures that indexed access works for copy resource sequences.
+ function readSequenceCopyElements() {
+ success = true;
+
+ var jsIntList = msco.generateIntSequence();
+ var jsQrealList = msco.generateQrealSequence();
+ var jsBoolList = msco.generateBoolSequence();
+ var jsStringList = msco.generateStringSequence();
+
+ intVal = jsIntList[1];
+ qrealVal = jsQrealList[1];
+ boolVal = jsBoolList[1];
+ stringVal = jsStringList[1];
+
+ if (intVal != 2)
+ success = false;
+ if (qrealVal != 2.2)
+ success = false;
+ if (boolVal != false)
+ success = false;
+ if (stringVal != "two")
+ success = false;
+ }
+
+ // this test ensures that equality works for copy resource sequences.
+ function testEqualitySemantics() {
+ success = true;
+
+ var jsIntList = msco.generateIntSequence();
+ var jsIntList2 = msco.generateIntSequence();
+
+ if (jsIntList == jsIntList2) success = false;
+ if (jsIntList != jsIntList) success = false;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/sequenceConversion.indexes.qml b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.indexes.qml
new file mode 100644
index 0000000000..23f1e90417
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.indexes.qml
@@ -0,0 +1,89 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ id: root
+ objectName: "root"
+
+ MySequenceConversionObject {
+ id: msco
+ objectName: "msco"
+ }
+
+ property bool success: false
+
+ function verifyExpected(array, idx) {
+ for (var i = 0; i < idx; ++i) {
+ if (array[i] != i) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ function indexedAccess() {
+ success = true;
+
+ msco.intListProperty = [ 0, 1, 2, 3, 4 ];
+ var expectedLength = msco.intListProperty.length;
+ var maxIndex = msco.maxIndex;
+ var tooBigIndex = msco.tooBigIndex;
+ var negativeIndex = msco.negativeIndex;
+
+ // shouldn't be able to set the length > maxIndex.
+ msco.intListProperty.length = tooBigIndex;
+ if (msco.intListProperty.length != expectedLength)
+ success = false;
+ if (!verifyExpected(msco.intListProperty, 4))
+ success = false;
+
+ // shouldn't be able to set any index > maxIndex.
+ msco.intListProperty[tooBigIndex] = 12;
+ if (msco.intListProperty.length != expectedLength)
+ success = false;
+ if (!verifyExpected(msco.intListProperty, 4))
+ success = false;
+
+ // shouldn't be able to access any index > maxIndex.
+ var valueAtTBI = msco.intListProperty[tooBigIndex];
+ if (valueAtTBI != undefined)
+ success = false;
+ if (!verifyExpected(msco.intListProperty, 4))
+ success = false;
+
+ // shouldn't be able to set the length to < 0
+ msco.intListProperty.length = negativeIndex;
+ if (msco.intListProperty.length != expectedLength)
+ success = false; // shouldn't have changed.
+ if (!verifyExpected(msco.intListProperty, 4))
+ success = false;
+
+ // shouldn't be able to set any index < 0.
+ msco.intListProperty[negativeIndex] = 12;
+ if (msco.intListProperty.length != expectedLength)
+ success = false;
+ if (!verifyExpected(msco.intListProperty, 4))
+ success = false;
+
+ // shouldn't be able to access any index < 0.
+ var valueAtNI = msco.intListProperty[negativeIndex];
+ if (valueAtNI != undefined)
+ success = false;
+ if (!verifyExpected(msco.intListProperty, 4))
+ success = false;
+
+ // NOTE: while these two operations are technically
+ // fine, we expect std::bad_alloc exceptions here
+ // which we handle in the sequence wrapper.
+ msco.intListProperty.length = maxIndex;
+ if (msco.intListProperty.length != expectedLength)
+ success = false;
+ if (!verifyExpected(msco.intListProperty, 4))
+ success = false;
+ msco.intListProperty[maxIndex] = 15;
+ if (msco.intListProperty.length != expectedLength)
+ success = false;
+ if (!verifyExpected(msco.intListProperty, 4))
+ success = false;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/sequenceConversion.read.error.qml b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.read.error.qml
new file mode 100644
index 0000000000..12a76d7e7d
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.read.error.qml
@@ -0,0 +1,21 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ id: root
+ objectName: "root"
+
+ MySequenceConversionObject {
+ id: msco
+ objectName: "msco"
+ }
+
+ property int pointListLength: 0
+ property variant pointList
+
+ function performTest() {
+ // we have NOT registered QList<QPoint> as a type
+ pointListLength = msco.pointListProperty.length;
+ pointList = msco.pointListProperty;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/sequenceConversion.read.qml b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.read.qml
new file mode 100644
index 0000000000..4a8a4a17b2
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.read.qml
@@ -0,0 +1,105 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ id: root
+ objectName: "root"
+
+ MySequenceConversionObject {
+ id: msco
+ objectName: "msco"
+ }
+
+ property int intListLength: 0
+ property variant intList
+ property int qrealListLength: 0
+ property variant qrealList
+ property int boolListLength: 0
+ property variant boolList
+ property int stringListLength: 0
+ property variant stringList
+ property int urlListLength: 0
+ property variant urlList
+ property int qstringListLength: 0
+ property variant qstringList
+
+ function readSequences() {
+ intListLength = msco.intListProperty.length;
+ intList = msco.intListProperty;
+ qrealListLength = msco.qrealListProperty.length;
+ qrealList = msco.qrealListProperty;
+ boolListLength = msco.boolListProperty.length;
+ boolList = msco.boolListProperty;
+ stringListLength = msco.stringListProperty.length;
+ stringList = msco.stringListProperty;
+ urlListLength = msco.urlListProperty.length;
+ urlList = msco.urlListProperty;
+ qstringListLength = msco.qstringListProperty.length;
+ qstringList = msco.qstringListProperty;
+ }
+
+ property int intVal
+ property real qrealVal
+ property bool boolVal
+ property string stringVal
+ property url urlVal
+ property string qstringVal
+
+ function readSequenceElements() {
+ intVal = msco.intListProperty[1];
+ qrealVal = msco.qrealListProperty[1];
+ boolVal = msco.boolListProperty[1];
+ stringVal = msco.stringListProperty[1];
+ urlVal = msco.urlListProperty[1];
+ qstringVal = msco.qstringListProperty[1];
+ }
+
+ property bool enumerationMatches
+ function enumerateSequenceElements() {
+ var jsIntList = [1, 2, 3, 4, 5];
+ msco.intListProperty = [1, 2, 3, 4, 5];
+
+ var jsIntListProps = []
+ var seqIntListProps = []
+
+ enumerationMatches = true;
+ for (var i in jsIntList) {
+ jsIntListProps.push(i);
+ if (jsIntList[i] != msco.intListProperty[i]) {
+ enumerationMatches = false;
+ }
+ }
+ for (var j in msco.intListProperty) {
+ seqIntListProps.push(j);
+ if (jsIntList[j] != msco.intListProperty[j]) {
+ enumerationMatches = false;
+ }
+ }
+
+ if (jsIntListProps.length != seqIntListProps.length) {
+ enumerationMatches = false;
+ }
+
+ var emptyList = [];
+ msco.stringListProperty = []
+ if (emptyList.toString() != msco.stringListProperty.toString()) {
+ enumerationMatches = false;
+ }
+ if (emptyList.valueOf() != msco.stringListProperty.valueOf()) {
+ enumerationMatches = false;
+ }
+ }
+
+ property bool referenceDeletion: false
+ function testReferenceDeletion() {
+ referenceDeletion = true;
+ var testObj = msco.generateTestObject();
+ testObj.intListProperty = [1, 2, 3, 4, 5];
+ var testSequence = testObj.intListProperty;
+ if (testSequence[4] != 5)
+ referenceDeletion = false;
+ msco.deleteTestObject(testObj); // delete referenced object.
+ if (testSequence[4] == 5)
+ referenceDeletion = false;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/sequenceConversion.threads.qml b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.threads.qml
new file mode 100644
index 0000000000..aefad89ca4
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.threads.qml
@@ -0,0 +1,74 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ id: root
+ objectName: "root"
+
+ MySequenceConversionObject {
+ id: msco
+ objectName: "msco"
+ }
+
+ property bool success: false
+ property bool finished: false
+
+ function testIntSequence() {
+ msco.intListProperty = [ 0, 1, 2, 3, 4, 5, 6, 7 ];
+ worker.sendSequence(msco.intListProperty);
+ }
+
+ function testQrealSequence() {
+ msco.qrealListProperty = [ 0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1 ];
+ worker.sendSequence(msco.qrealListProperty);
+ }
+
+ function testBoolSequence() {
+ msco.boolListProperty = [ false, true, true, false, false, true, false, true ];
+ worker.sendSequence(msco.boolListProperty);
+ }
+
+ function testStringSequence() {
+ msco.stringListProperty = [ "one", "two", "three", "four" ];
+ worker.sendSequence(msco.stringListProperty);
+ }
+
+ function testQStringSequence() {
+ msco.qstringListProperty = [ "one", "two", "three", "four" ];
+ worker.sendSequence(msco.qstringListProperty);
+ }
+
+ function testUrlSequence() {
+ msco.urlListProperty = [ "www.example1.com", "www.example2.com", "www.example3.com", "www.example4.com" ];
+ worker.sendSequence(msco.urlListProperty);
+ }
+
+ function testVariantSequence() {
+ msco.variantListProperty = [ "one", true, 3, "four" ];
+ worker.sendSequence(msco.variantListProperty);
+ }
+
+ WorkerScript {
+ id: worker
+ source: "threadScript.js"
+
+ property variant expected
+ property variant response
+
+ function sendSequence(seq) {
+ root.success = false;
+ root.finished = false;
+ worker.expected = seq;
+ worker.sendMessage(seq);
+ }
+
+ onMessage: {
+ worker.response = messageObject;
+ if (worker.response.toString() == worker.expected.toString())
+ root.success = true;
+ else
+ root.success = false;
+ root.finished = true;
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/sequenceConversion.write.error.qml b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.write.error.qml
new file mode 100644
index 0000000000..75beafd1ee
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.write.error.qml
@@ -0,0 +1,18 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ id: root
+ objectName: "root"
+
+ MySequenceConversionObject {
+ id: msco
+ objectName: "msco"
+ }
+
+ function performTest() {
+ // we have NOT registered QList<QPoint> as a type
+ var pointList = [ Qt.point(7,7), Qt.point(8,8), Qt.point(9,9) ];
+ msco.pointListProperty = pointList; // error.
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/sequenceConversion.write.qml b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.write.qml
new file mode 100644
index 0000000000..812de043b7
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.write.qml
@@ -0,0 +1,109 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ id: root
+ objectName: "root"
+
+ MySequenceConversionObject {
+ id: msco
+ objectName: "msco"
+ }
+
+ property bool success
+
+ function writeSequences() {
+ success = true;
+
+ var intList = [ 9, 8, 7, 6 ];
+ msco.intListProperty = intList;
+ var qrealList = [ 9.9, 8.8, 7.7, 6.6 ];
+ msco.qrealListProperty = qrealList;
+ var boolList = [ false, false, false, true ];
+ msco.boolListProperty = boolList;
+ var stringList = [ "nine", "eight", "seven", "six" ]
+ msco.stringListProperty = stringList;
+ var urlList = [ "http://www.example9.com", "http://www.example8.com", "http://www.example7.com", "http://www.example6.com" ]
+ msco.urlListProperty = urlList;
+ var qstringList = [ "nine", "eight", "seven", "six" ]
+ msco.qstringListProperty = qstringList;
+
+ if (msco.intListProperty[0] != 9 || msco.intListProperty[1] != 8 || msco.intListProperty[2] != 7 || msco.intListProperty[3] != 6)
+ success = false;
+ if (msco.qrealListProperty[0] != 9.9 || msco.qrealListProperty[1] != 8.8 || msco.qrealListProperty[2] != 7.7 || msco.qrealListProperty[3] != 6.6)
+ success = false;
+ if (msco.boolListProperty[0] != false || msco.boolListProperty[1] != false || msco.boolListProperty[2] != false || msco.boolListProperty[3] != true)
+ success = false;
+ if (msco.stringListProperty[0] != "nine" || msco.stringListProperty[1] != "eight" || msco.stringListProperty[2] != "seven" || msco.stringListProperty[3] != "six")
+ success = false;
+ if (msco.urlListProperty[0] != "http://www.example9.com" || msco.urlListProperty[1] != "http://www.example8.com" || msco.urlListProperty[2] != "http://www.example7.com" || msco.urlListProperty[3] != "http://www.example6.com")
+ success = false;
+ if (msco.qstringListProperty[0] != "nine" || msco.qstringListProperty[1] != "eight" || msco.qstringListProperty[2] != "seven" || msco.qstringListProperty[3] != "six")
+ success = false;
+ }
+
+ function writeSequenceElements() {
+ // set up initial conditions.
+ writeSequences();
+ success = true;
+
+ // element set.
+ msco.intListProperty[3] = 2;
+ msco.qrealListProperty[3] = 2.2;
+ msco.boolListProperty[3] = false;
+ msco.stringListProperty[3] = "changed";
+ msco.urlListProperty[3] = "http://www.examplechanged.com";
+ msco.qstringListProperty[3] = "changed";
+
+ if (msco.intListProperty[0] != 9 || msco.intListProperty[1] != 8 || msco.intListProperty[2] != 7 || msco.intListProperty[3] != 2)
+ success = false;
+ if (msco.qrealListProperty[0] != 9.9 || msco.qrealListProperty[1] != 8.8 || msco.qrealListProperty[2] != 7.7 || msco.qrealListProperty[3] != 2.2)
+ success = false;
+ if (msco.boolListProperty[0] != false || msco.boolListProperty[1] != false || msco.boolListProperty[2] != false || msco.boolListProperty[3] != false)
+ success = false;
+ if (msco.stringListProperty[0] != "nine" || msco.stringListProperty[1] != "eight" || msco.stringListProperty[2] != "seven" || msco.stringListProperty[3] != "changed")
+ success = false;
+ if (msco.urlListProperty[0] != "http://www.example9.com" || msco.urlListProperty[1] != "http://www.example8.com" || msco.urlListProperty[2] != "http://www.example7.com" || msco.urlListProperty[3] != "http://www.examplechanged.com")
+ success = false;
+ if (msco.qstringListProperty[0] != "nine" || msco.qstringListProperty[1] != "eight" || msco.qstringListProperty[2] != "seven" || msco.qstringListProperty[3] != "changed")
+ success = false;
+ }
+
+ function writeOtherElements() {
+ success = true;
+ var jsIntList = [1, 2, 3, 4, 5];
+ msco.intListProperty = [1, 2, 3, 4, 5];
+
+ jsIntList[8] = 8;
+ msco.intListProperty[8] = 8;
+ if (jsIntList[8] != msco.intListProperty[8])
+ success = false;
+ if (jsIntList.length != msco.intListProperty.length)
+ success = false;
+
+ // NOTE: we can't exactly match the spec here -- we fill the sequence with a default (rather than empty) value
+ if (msco.intListProperty[5] != 0 || msco.intListProperty[6] != 0 || msco.intListProperty[7] != 0)
+ success = false;
+
+ // should have no effect
+ var currLength = jsIntList.length;
+ jsIntList.someThing = 9;
+ msco.intListProperty.someThing = 9;
+ if (msco.intListProperty.length != currLength)
+ success = false;
+ }
+
+ property bool referenceDeletion: false
+ function testReferenceDeletion() {
+ referenceDeletion = true;
+ var testObj = msco.generateTestObject();
+ testObj.intListProperty = [1, 2, 3, 4, 5];
+ var testSequence = testObj.intListProperty;
+ if (testSequence[4] != 5)
+ referenceDeletion = false;
+ msco.deleteTestObject(testObj); // delete referenced object.
+ testSequence[4] = 5; // shouldn't work, since referenced object no longer exists.
+ if (testSequence[4] == 5)
+ referenceDeletion = false;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/sharedAttachedObject.qml b/tests/auto/qml/qqmlecmascript/data/sharedAttachedObject.qml
new file mode 100644
index 0000000000..b967f0984c
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/sharedAttachedObject.qml
@@ -0,0 +1,16 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+MyQmlObject {
+ id: root
+ property bool test1: false
+ property bool test2: false
+
+ MyQmlObject.value2: 7
+
+ Component.onCompleted: {
+ test1 = root.MyQmlObject.value2 == 7;
+ test2 = root.MyQmlObjectAlias.value2 == 7;
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/shutdownErrors.qml b/tests/auto/qml/qqmlecmascript/data/shutdownErrors.qml
new file mode 100644
index 0000000000..b30aa8b4cd
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/shutdownErrors.qml
@@ -0,0 +1,13 @@
+import QtQuick 2.0
+
+Item {
+ property int test: myObject.object.a
+
+ Item {
+ id: myObject
+ property QtObject object;
+ object: QtObject {
+ property int a: 10
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/signalAssignment.1.qml b/tests/auto/qml/qqmlecmascript/data/signalAssignment.1.qml
new file mode 100644
index 0000000000..fbd09142f7
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/signalAssignment.1.qml
@@ -0,0 +1,5 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ onBasicSignal: setString('pass')
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/signalAssignment.2.qml b/tests/auto/qml/qqmlecmascript/data/signalAssignment.2.qml
new file mode 100644
index 0000000000..6467c42bb9
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/signalAssignment.2.qml
@@ -0,0 +1,5 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ onArgumentSignal: setString('pass ' + a + ' ' + b + ' ' + c + ' ' + d + ' ' + e)
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/signalAssignment.3.qml b/tests/auto/qml/qqmlecmascript/data/signalAssignment.3.qml
new file mode 100644
index 0000000000..690b7cf216
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/signalAssignment.3.qml
@@ -0,0 +1,5 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ onUnnamedArgumentSignal: setString('pass ' + a + ' ' + c)
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/signalAssignment.4.qml b/tests/auto/qml/qqmlecmascript/data/signalAssignment.4.qml
new file mode 100644
index 0000000000..0e1e728a86
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/signalAssignment.4.qml
@@ -0,0 +1,6 @@
+import Qt.test 1.0
+
+
+MyQmlObject {
+ onSignalWithGlobalName: setString('pass ' + parseInt("5"))
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/signalHandlers.qml b/tests/auto/qml/qqmlecmascript/data/signalHandlers.qml
new file mode 100644
index 0000000000..975be1b2ad
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/signalHandlers.qml
@@ -0,0 +1,60 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+QtObject {
+ id: root
+
+ property int count: 0
+ signal testSignal
+ onTestSignal: count++
+
+ property int funcCount: 0
+ function testFunction() {
+ funcCount++;
+ }
+
+ //should increment count
+ function testSignalCall() {
+ testSignal()
+ }
+
+ //should NOT increment count, and should throw an exception
+ property string errorString
+ function testSignalHandlerCall() {
+ try {
+ onTestSignal()
+ } catch (error) {
+ errorString = error.toString();
+ }
+ }
+
+ //should increment funcCount once
+ function testSignalConnection() {
+ testSignal.connect(testFunction)
+ testSignal();
+ testSignal.disconnect(testFunction)
+ testSignal();
+ }
+
+ //should increment funcCount once
+ function testSignalHandlerConnection() {
+ onTestSignal.connect(testFunction)
+ testSignal();
+ onTestSignal.disconnect(testFunction)
+ testSignal();
+ }
+
+ //should be defined
+ property bool definedResult: false
+ function testSignalDefined() {
+ if (testSignal !== undefined)
+ definedResult = true;
+ }
+
+ //should be defined
+ property bool definedHandlerResult: false
+ function testSignalHandlerDefined() {
+ if (onTestSignal !== undefined)
+ definedHandlerResult = true;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/signalParameterTypes.qml b/tests/auto/qml/qqmlecmascript/data/signalParameterTypes.qml
new file mode 100644
index 0000000000..4fc2dab943
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/signalParameterTypes.qml
@@ -0,0 +1,18 @@
+import Qt.test 1.0
+
+MyQmlObject
+{
+ id: root
+ property int intProperty
+ property real realProperty
+ property color colorProperty
+ property variant variantProperty
+ property int enumProperty
+ property int qtEnumProperty
+
+ signal mySignal(int a, real b, color c, variant d, int e, int f)
+
+ onMySignal: { intProperty = a; realProperty = b; colorProperty = c; variantProperty = d; enumProperty = e; qtEnumProperty = f; }
+
+ onBasicSignal: root.mySignal(10, 19.2, Qt.rgba(1, 1, 0, 1), Qt.rgba(1, 0, 1, 1), MyQmlObject.EnumValue3, Qt.LeftButton)
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/signalTriggeredBindings.qml b/tests/auto/qml/qqmlecmascript/data/signalTriggeredBindings.qml
new file mode 100644
index 0000000000..d98d7e9c81
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/signalTriggeredBindings.qml
@@ -0,0 +1,20 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+MyQmlObject {
+ property real base: 50
+ property alias test1: myObject.test1
+ property alias test2: myObject.test2
+
+ objectProperty: QtObject {
+ id: myObject
+ property real test1: base
+ property real test2: Math.max(0, base)
+ }
+
+ // Signal with no args
+ onBasicSignal: base = 200
+ // Signal with args
+ onArgumentSignal: base = 400
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/signalWithJSValueInVariant.qml b/tests/auto/qml/qqmlecmascript/data/signalWithJSValueInVariant.qml
new file mode 100644
index 0000000000..a6f1aa381a
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/signalWithJSValueInVariant.qml
@@ -0,0 +1,12 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ property string expression
+ property string compare
+ property bool pass: false
+ onSignalWithVariant:
+ {
+ var expected = eval(expression);
+ pass = eval(compare)(arg, expected);
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/signalWithQJSValue.qml b/tests/auto/qml/qqmlecmascript/data/signalWithQJSValue.qml
new file mode 100644
index 0000000000..36f481d533
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/signalWithQJSValue.qml
@@ -0,0 +1,14 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ property string expression
+ property string compare
+ property bool pass: false
+
+ onSignalWithQJSValue:
+ {
+ qjsvalueMethod(arg);
+ var expected = eval(expression);
+ pass = eval(compare)(arg, expected);
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/signalWithUnknownTypes.qml b/tests/auto/qml/qqmlecmascript/data/signalWithUnknownTypes.qml
new file mode 100644
index 0000000000..49293edfb3
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/signalWithUnknownTypes.qml
@@ -0,0 +1,5 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ onSignalWithUnknownType: variantMethod(arg);
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/strictlyEquals.qml b/tests/auto/qml/qqmlecmascript/data/strictlyEquals.qml
new file mode 100644
index 0000000000..e709e3a8bd
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/strictlyEquals.qml
@@ -0,0 +1,17 @@
+import QtQuick 2.0
+
+QtObject {
+ property bool test1: (a === true)
+ property bool test2: !(a === false)
+ property bool test3: (b === 11.2)
+ property bool test4: !(b === 9)
+ property bool test5: (c === 9)
+ property bool test6: !(c === 13)
+ property bool test7: (d === "Hello world")
+ property bool test8: !(d === "Hi")
+
+ property bool a: true
+ property real b: 11.2
+ property int c: 9
+ property string d: "Hello world"
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/stringArg.qml b/tests/auto/qml/qqmlecmascript/data/stringArg.qml
new file mode 100644
index 0000000000..7019af9da5
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/stringArg.qml
@@ -0,0 +1,49 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+ property bool returnValue: false
+
+ property string first
+ property string second
+ property string third
+ property string fourth
+ property string fifth
+ property string sixth
+ property string seventh
+ property string eighth
+ property string ninth
+
+ function success() {
+ var a = "Value is %1";
+ for (var ii = 0; ii < 10; ++ii) {
+ first = a.arg("string");
+ second = a.arg(1);
+ third = a.arg(true);
+ fourth = a.arg(3.345);
+ fifth = a.arg(undefined);
+ sixth = a.arg(null);
+ seventh = a.arg({"test":5});
+ eighth = a.arg({"test":5, "again":6});
+ }
+
+ if (first != "Value is string") returnValue = false;
+ if (second != "Value is 1") returnValue = false;
+ if (third != "Value is true") returnValue = false;
+ if (fourth != "Value is 3.345") returnValue = false;
+ if (fifth != "Value is undefined") returnValue = false;
+ if (sixth != "Value is null") returnValue = false;
+ if (seventh != "Value is [Object object]") returnValue = false;
+ if (eighth != "Value is [Object object]") returnValue = false;
+ returnValue = true;
+ }
+
+ function failure() {
+ returnValue = true;
+ var a = "Value is %1";
+ for (var ii = 0; ii < 10; ++ii) {
+ ninth = a.arg(1,2,3,4);
+ }
+ returnValue = false;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/switchStatement.1.qml b/tests/auto/qml/qqmlecmascript/data/switchStatement.1.qml
new file mode 100644
index 0000000000..3c7870839d
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/switchStatement.1.qml
@@ -0,0 +1,33 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ value: {
+ var value = 0
+ switch (stringProperty) {
+ case "A":
+ value = value + 1
+ value = value + 1
+ /* should fall through */
+ case "S":
+ value = value + 1
+ value = value + 1
+ value = value + 1
+ break;
+ case "D": { // with curly braces
+ value = value + 1
+ value = value + 1
+ value = value + 1
+ break;
+ }
+ case "F": {
+ value = value + 1
+ value = value + 1
+ value = value + 1
+ }
+ /* should fall through */
+ default:
+ value = value + 1
+ }
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/switchStatement.2.qml b/tests/auto/qml/qqmlecmascript/data/switchStatement.2.qml
new file mode 100644
index 0000000000..928d36be1f
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/switchStatement.2.qml
@@ -0,0 +1,33 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ value: {
+ var value = 0
+ switch (stringProperty) {
+ case "A":
+ value = value + 1
+ value = value + 1
+ /* should fall through */
+ case "S":
+ value = value + 1
+ value = value + 1
+ value = value + 1
+ break;
+ default:
+ value = value + 1
+ case "D": { // with curly braces
+ value = value + 1
+ value = value + 1
+ value = value + 1
+ break;
+ }
+ case "F": {
+ value = value + 1
+ value = value + 1
+ value = value + 1
+ }
+ /* should fall through */
+ }
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/switchStatement.3.qml b/tests/auto/qml/qqmlecmascript/data/switchStatement.3.qml
new file mode 100644
index 0000000000..5b05d88767
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/switchStatement.3.qml
@@ -0,0 +1,33 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ value: {
+ var value = 0
+ switch (stringProperty) {
+ default:
+ value = value + 1
+ case "A":
+ value = value + 1
+ value = value + 1
+ /* should fall through */
+ case "S":
+ value = value + 1
+ value = value + 1
+ value = value + 1
+ break;
+ case "D": { // with curly braces
+ value = value + 1
+ value = value + 1
+ value = value + 1
+ break;
+ }
+ case "F": {
+ value = value + 1
+ value = value + 1
+ value = value + 1
+ }
+ /* should fall through */
+ }
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/switchStatement.4.qml b/tests/auto/qml/qqmlecmascript/data/switchStatement.4.qml
new file mode 100644
index 0000000000..43ba199a04
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/switchStatement.4.qml
@@ -0,0 +1,31 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ value: {
+ var value = 0
+ switch (stringProperty) {
+ case "A":
+ value = value + 1
+ value = value + 1
+ /* should fall through */
+ case "S":
+ value = value + 1
+ value = value + 1
+ value = value + 1
+ break;
+ case "D": { // with curly braces
+ value = value + 1
+ value = value + 1
+ value = value + 1
+ break;
+ }
+ case "F": {
+ value = value + 1
+ value = value + 1
+ value = value + 1
+ }
+ /* should fall through */
+ }
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/switchStatement.5.qml b/tests/auto/qml/qqmlecmascript/data/switchStatement.5.qml
new file mode 100644
index 0000000000..e0fc62e392
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/switchStatement.5.qml
@@ -0,0 +1,12 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ value: {
+ var value = 0
+ switch (stringProperty) {
+ default:
+ value = value + 1
+ }
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/switchStatement.6.qml b/tests/auto/qml/qqmlecmascript/data/switchStatement.6.qml
new file mode 100644
index 0000000000..6fb71eb345
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/switchStatement.6.qml
@@ -0,0 +1,13 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ function one(kind) { return 123 }
+ function two(kind) { return 321 }
+
+ value: switch (stringProperty) {
+ case "A": case "S": one(stringProperty); break;
+ case "D": case "F": two(stringProperty); break;
+ default: 0
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/threadScript.js b/tests/auto/qml/qqmlecmascript/data/threadScript.js
new file mode 100644
index 0000000000..9f94de1bc1
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/threadScript.js
@@ -0,0 +1,4 @@
+WorkerScript.onMessage = function(msg) {
+ WorkerScript.sendMessage(msg);
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/transientErrors.2.qml b/tests/auto/qml/qqmlecmascript/data/transientErrors.2.qml
new file mode 100644
index 0000000000..c44acf4fd1
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/transientErrors.2.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+
+QtObject {
+ id: root
+
+ property variant a: 10
+ property int x: 10
+ property int test: a.x
+
+ Component.onCompleted: {
+ a = 11;
+ a = root;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/transientErrors.qml b/tests/auto/qml/qqmlecmascript/data/transientErrors.qml
new file mode 100644
index 0000000000..451bb51996
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/transientErrors.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.0
+
+QtObject {
+ property variant obj: nested
+
+ property variant obj2
+ obj2: NestedTypeTransientErrors {
+ id: nested
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/tryStatement.1.qml b/tests/auto/qml/qqmlecmascript/data/tryStatement.1.qml
new file mode 100644
index 0000000000..71cc67a941
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/tryStatement.1.qml
@@ -0,0 +1,13 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ property int defaultValue: 123
+
+ function go() {
+ undefinedObject.method() // this call will throw an exception
+ return 321
+ }
+
+ value: try { go() } catch(e) { defaultValue }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/tryStatement.2.qml b/tests/auto/qml/qqmlecmascript/data/tryStatement.2.qml
new file mode 100644
index 0000000000..e7fca0bff7
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/tryStatement.2.qml
@@ -0,0 +1,11 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ property int defaultValue: 123
+
+ function go() {
+ return 321
+ }
+
+ value: try { go() } catch(e) { defaultValue }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/tryStatement.3.qml b/tests/auto/qml/qqmlecmascript/data/tryStatement.3.qml
new file mode 100644
index 0000000000..04b39f73d5
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/tryStatement.3.qml
@@ -0,0 +1,13 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ property int defaultValue: 123
+
+ function go() {
+ undefinedObject.method() // this call will throw an exception
+ return 321
+ }
+
+ value: 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
new file mode 100644
index 0000000000..231aaf0683
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/tryStatement.4.qml
@@ -0,0 +1,12 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ property int defaultValue: 123
+
+ function go() {
+ return 321
+ }
+
+ value: try { var p = go() } catch(e) { var p = defaultValue } finally { p == 321 }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/typeOf.js b/tests/auto/qml/qqmlecmascript/data/typeOf.js
new file mode 100644
index 0000000000..16a34234c0
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/typeOf.js
@@ -0,0 +1,25 @@
+var test1 = typeof a
+
+var b = {}
+var test2 = typeof b
+
+var c = 5
+var test3 = typeof c
+
+var d = "hello world"
+var test4 = typeof d
+
+var e = function() {}
+var test5 = typeof e
+
+var f = null
+var test6 = typeof f
+
+var g = undefined
+var test7 = typeof g
+
+var h = true
+var test8 = typeof h
+
+var i = []
+var test9 = typeof i
diff --git a/tests/auto/qml/qqmlecmascript/data/typeOf.qml b/tests/auto/qml/qqmlecmascript/data/typeOf.qml
new file mode 100644
index 0000000000..28f7debed5
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/typeOf.qml
@@ -0,0 +1,26 @@
+import QtQuick 2.0
+import "typeOf.js" as TypeOf
+
+QtObject {
+ property string test1
+ property string test2
+ property string test3
+ property string test4
+ property string test5
+ property string test6
+ property string test7
+ property string test8
+ property string test9
+
+ Component.onCompleted: {
+ test1 = TypeOf.test1
+ test2 = TypeOf.test2
+ test3 = TypeOf.test3
+ test4 = TypeOf.test4
+ test5 = TypeOf.test5
+ test6 = TypeOf.test6
+ test7 = TypeOf.test7
+ test8 = TypeOf.test8
+ test9 = TypeOf.test9
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/unaryExpression.qml b/tests/auto/qml/qqmlecmascript/data/unaryExpression.qml
new file mode 100644
index 0000000000..0d40bec710
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/unaryExpression.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+
+Item {
+
+ Component.onCompleted:
+++bar
+
+ property int bar: 0
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/undefinedResetsProperty.2.qml b/tests/auto/qml/qqmlecmascript/data/undefinedResetsProperty.2.qml
new file mode 100644
index 0000000000..e73d38e2ce
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/undefinedResetsProperty.2.qml
@@ -0,0 +1,10 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ resettableProperty: 19
+
+ function doReset() {
+ resettableProperty = undefined;
+ }
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/undefinedResetsProperty.qml b/tests/auto/qml/qqmlecmascript/data/undefinedResetsProperty.qml
new file mode 100644
index 0000000000..eceff60aa1
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/undefinedResetsProperty.qml
@@ -0,0 +1,7 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ property bool setUndefined: false
+
+ resettableProperty: setUndefined?undefined:92
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/urlListProperty.qml b/tests/auto/qml/qqmlecmascript/data/urlListProperty.qml
new file mode 100644
index 0000000000..eeb0815f09
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/urlListProperty.qml
@@ -0,0 +1,41 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Item {
+ // single url assignment to url list property
+ MySequenceConversionObject {
+ id: msco1
+ objectName: "msco1"
+ }
+
+ // single url binding to url list property
+ MySequenceConversionObject {
+ id: msco2
+ objectName: "msco2"
+ urlListProperty: "http://qt-project.org/?get%3cDATA%3e";
+ }
+
+ // multiple url assignment to url list property
+ MySequenceConversionObject {
+ id: msco3
+ objectName: "msco3"
+ }
+
+ // multiple url binding to url list property
+ MySequenceConversionObject {
+ id: msco4
+ objectName: "msco4"
+ urlListProperty: [
+ "http://qt-project.org/?get%3cDATA%3e",
+ "http://qt-project.org/?get%3cDATA%3e"
+ ];
+ }
+
+ Component.onCompleted: {
+ msco1.urlListProperty = "http://qt-project.org/?get%3cDATA%3e";
+ msco3.urlListProperty = [
+ "http://qt-project.org/?get%3cDATA%3e",
+ "http://qt-project.org/?get%3cDATA%3e"
+ ];
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/urlProperty.1.qml b/tests/auto/qml/qqmlecmascript/data/urlProperty.1.qml
new file mode 100644
index 0000000000..451cb03206
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/urlProperty.1.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+MyQmlObject {
+ property bool result
+ urlProperty: stringProperty + "/index.html"
+ intProperty: if (urlProperty) 123; else 321
+ value: urlProperty == stringProperty + "/index.html"
+ result: urlProperty == urlProperty
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/urlProperty.2.qml b/tests/auto/qml/qqmlecmascript/data/urlProperty.2.qml
new file mode 100644
index 0000000000..0e8bdaec96
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/urlProperty.2.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+MyQmlObject {
+ property bool result
+ stringProperty: "http://example.org"
+ urlProperty: stringProperty + "/?get%3cDATA%3e"
+ value: urlProperty == stringProperty + "/?get%3cDATA%3e"
+ result: urlProperty == urlProperty
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/v8bindingException.qml b/tests/auto/qml/qqmlecmascript/data/v8bindingException.qml
new file mode 100644
index 0000000000..ff203e23e3
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/v8bindingException.qml
@@ -0,0 +1,21 @@
+import QtQuick 2.0
+
+// This test uses a multi-line string which has \r-terminated
+// string fragments. The expression rewriter deliberately doesn't
+// handle \r-terminated string fragments (see QTBUG-24064) and thus
+// this test ensures that we don't crash when we encounter a
+// non-compilable binding such as this one.
+
+Item {
+ id: root
+
+ Component {
+ id: comp
+ Text {
+ property var value: ","
+ text: 'multi line ' + value + 'str ings'
+ }
+ }
+
+ Component.onCompleted: comp.createObject(root, { "value": undefined })
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/v8functionException.qml b/tests/auto/qml/qqmlecmascript/data/v8functionException.qml
new file mode 100644
index 0000000000..51df1c65d8
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/v8functionException.qml
@@ -0,0 +1,15 @@
+import QtQuick 2.0
+
+// This test uses a multi-line string which has \r-terminated
+// string fragments. The expression rewriter deliberately doesn't
+// handle \r-terminated string fragments (see QTBUG-24064) and thus
+// this test ensures that we don't crash when the client attempts
+// to invoke a non-compiled dynamic slot.
+
+Item {
+ id: root
+
+ function dynamicSlot() {
+ var someString = "Hello, this is a multiline string";
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/valueTypeFunctions.qml b/tests/auto/qml/qqmlecmascript/data/valueTypeFunctions.qml
new file mode 100644
index 0000000000..33b4a68c40
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/valueTypeFunctions.qml
@@ -0,0 +1,6 @@
+import Qt.test 1.0
+
+MyTypeObject {
+ rectProperty: Qt.rect(0,0,100,100)
+ rectFProperty: Qt.rect(0,0.5,100,99.5)
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/variantsAssignedUndefined.qml b/tests/auto/qml/qqmlecmascript/data/variantsAssignedUndefined.qml
new file mode 100644
index 0000000000..6aa8480365
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/variantsAssignedUndefined.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+
+QtObject {
+ property bool runTest: false
+ onRunTestChanged: test1 = undefined
+
+ property variant test1: 10
+ property variant test2: (runTest == false)?11:undefined
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/withStatement.1.qml b/tests/auto/qml/qqmlecmascript/data/withStatement.1.qml
new file mode 100644
index 0000000000..28f0c08451
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/withStatement.1.qml
@@ -0,0 +1,14 @@
+import Qt.test 1.0
+
+MyQmlObject {
+ property var other: MyQmlObject {
+ intProperty: 123
+
+ function go() {
+ return intProperty;
+ }
+ }
+
+ value: with(other) go()
+}
+
diff --git a/tests/auto/qml/qqmlecmascript/data/writeAttachedProperty.qml b/tests/auto/qml/qqmlecmascript/data/writeAttachedProperty.qml
new file mode 100644
index 0000000000..3854b069a0
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/writeAttachedProperty.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+QtObject {
+ function writeValue2() { MyQmlObject.value2 = 9 }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/writeRemovesBinding.qml b/tests/auto/qml/qqmlecmascript/data/writeRemovesBinding.qml
new file mode 100644
index 0000000000..a1ba5df071
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/writeRemovesBinding.qml
@@ -0,0 +1,46 @@
+import QtQuick 2.0
+
+QtObject {
+ id: root
+
+ property bool test: false
+
+ property real data: 9
+ property real binding: data
+
+ property alias aliasProperty: root.aliasBinding
+ property real aliasBinding: data
+
+ Component.onCompleted: {
+ // Non-aliased properties
+ if (binding != 9) return;
+
+ data = 11;
+ if (binding != 11) return;
+
+ binding = 6;
+ if (binding != 6) return;
+
+ data = 3;
+ if (binding != 6) return;
+
+
+ // Writing through an aliased property
+ if (aliasProperty != 3) return;
+ if (aliasBinding != 3) return;
+
+ data = 4;
+ if (aliasProperty != 4) return;
+ if (aliasBinding != 4) return;
+
+ aliasProperty = 19;
+ if (aliasProperty != 19) return;
+ if (aliasBinding != 19) return;
+
+ data = 5;
+ if (aliasProperty != 19) return;
+ if (aliasBinding != 19) return;
+
+ test = true;
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/qqmlecmascript.pro b/tests/auto/qml/qqmlecmascript/qqmlecmascript.pro
new file mode 100644
index 0000000000..b07e4393a9
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/qqmlecmascript.pro
@@ -0,0 +1,22 @@
+CONFIG += testcase
+TARGET = tst_qqmlecmascript
+macx:CONFIG -= app_bundle
+
+SOURCES += tst_qqmlecmascript.cpp \
+ testtypes.cpp \
+ ../../shared/testhttpserver.cpp
+HEADERS += testtypes.h \
+ ../../shared/testhttpserver.h
+INCLUDEPATH += ../../shared
+
+include (../../shared/util.pri)
+
+# QMAKE_CXXFLAGS = -fprofile-arcs -ftest-coverage
+# LIBS += -lgcov
+
+testDataFiles.files = data
+testDataFiles.path = .
+DEPLOYMENT += testDataFiles
+
+CONFIG += parallel_test
+QT += core-private gui-private v8-private qml-private network widgets testlib
diff --git a/tests/auto/qml/qqmlecmascript/testtypes.cpp b/tests/auto/qml/qqmlecmascript/testtypes.cpp
new file mode 100644
index 0000000000..78119cb776
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/testtypes.cpp
@@ -0,0 +1,210 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "testtypes.h"
+#include <QWidget>
+#include <QPlainTextEdit>
+#include <QQmlEngine>
+#include <QJSEngine>
+
+class BaseExtensionObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int baseExtendedProperty READ extendedProperty WRITE setExtendedProperty NOTIFY extendedPropertyChanged)
+public:
+ BaseExtensionObject(QObject *parent) : QObject(parent), m_value(0) {}
+
+ int extendedProperty() const { return m_value; }
+ void setExtendedProperty(int v) { m_value = v; emit extendedPropertyChanged(); }
+
+signals:
+ void extendedPropertyChanged();
+private:
+ int m_value;
+};
+
+class ExtensionObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int extendedProperty READ extendedProperty WRITE setExtendedProperty NOTIFY extendedPropertyChanged)
+public:
+ ExtensionObject(QObject *parent) : QObject(parent), m_value(0) {}
+
+ int extendedProperty() const { return m_value; }
+ void setExtendedProperty(int v) { m_value = v; emit extendedPropertyChanged(); }
+
+signals:
+ void extendedPropertyChanged();
+private:
+ int m_value;
+};
+
+class DefaultPropertyExtensionObject : public QObject
+{
+ Q_OBJECT
+ Q_CLASSINFO("DefaultProperty", "firstProperty")
+public:
+ DefaultPropertyExtensionObject(QObject *parent) : QObject(parent) {}
+};
+
+class QWidgetDeclarativeUI : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int width READ width WRITE setWidth NOTIFY widthChanged)
+
+signals:
+ void widthChanged();
+
+public:
+ QWidgetDeclarativeUI(QObject *other) : QObject(other) { }
+
+public:
+ int width() const { return 0; }
+ void setWidth(int) { }
+};
+
+void MyQmlObject::v8function(QQmlV8Function *args)
+{
+ const char *error = "Exception thrown from within QObject slot";
+ v8::ThrowException(v8::Exception::Error(v8::String::New(error)));
+}
+
+static QJSValue script_api(QQmlEngine *engine, QJSEngine *scriptEngine)
+{
+ Q_UNUSED(engine)
+
+ static int testProperty = 13;
+ QJSValue v = scriptEngine->newObject();
+ v.setProperty("scriptTestProperty", testProperty++);
+ return v;
+}
+
+static QJSValue readonly_script_api(QQmlEngine *engine, QJSEngine *scriptEngine)
+{
+ Q_UNUSED(engine)
+
+ static int testProperty = 42;
+ QJSValue v = scriptEngine->newObject();
+ v.setProperty("scriptTestProperty", testProperty++);
+
+ // now freeze it so that it's read-only
+ QJSValue freezeFunction = scriptEngine->evaluate("(function(obj) { return Object.freeze(obj); })");
+ v = freezeFunction.call(QJSValueList() << v);
+
+ return v;
+}
+
+static QObject *qobject_api(QQmlEngine *engine, QJSEngine *scriptEngine)
+{
+ Q_UNUSED(engine)
+ Q_UNUSED(scriptEngine)
+
+ testQObjectApi *o = new testQObjectApi();
+ o->setQObjectTestProperty(20);
+ o->setQObjectTestWritableProperty(50);
+ return o;
+}
+
+static QObject *qobject_api_engine_parent(QQmlEngine *engine, QJSEngine *scriptEngine)
+{
+ Q_UNUSED(scriptEngine)
+
+ static int testProperty = 26;
+ testQObjectApi *o = new testQObjectApi(engine);
+ o->setQObjectTestProperty(testProperty++);
+ return o;
+}
+
+void registerTypes()
+{
+ qmlRegisterType<MyQmlObject>("Qt.test", 1,0, "MyQmlObjectAlias");
+ qmlRegisterType<MyQmlObject>("Qt.test", 1,0, "MyQmlObject");
+ qmlRegisterType<MyDeferredObject>("Qt.test", 1,0, "MyDeferredObject");
+ qmlRegisterType<MyQmlContainer>("Qt.test", 1,0, "MyQmlContainer");
+ qmlRegisterExtendedType<MyBaseExtendedObject, BaseExtensionObject>("Qt.test", 1,0, "MyBaseExtendedObject");
+ qmlRegisterExtendedType<MyExtendedObject, ExtensionObject>("Qt.test", 1,0, "MyExtendedObject");
+ qmlRegisterType<MyTypeObject>("Qt.test", 1,0, "MyTypeObject");
+ qmlRegisterType<MyDerivedObject>("Qt.test", 1,0, "MyDerivedObject");
+ qmlRegisterType<NumberAssignment>("Qt.test", 1,0, "NumberAssignment");
+ qmlRegisterExtendedType<DefaultPropertyExtendedObject, DefaultPropertyExtensionObject>("Qt.test", 1,0, "DefaultPropertyExtendedObject");
+ qmlRegisterType<OverrideDefaultPropertyObject>("Qt.test", 1,0, "OverrideDefaultPropertyObject");
+ qmlRegisterType<MyRevisionedClass>("Qt.test",1,0,"MyRevisionedClass");
+ qmlRegisterType<MyDeleteObject>("Qt.test", 1,0, "MyDeleteObject");
+ qmlRegisterType<MyRevisionedClass,1>("Qt.test",1,1,"MyRevisionedClass");
+
+ // test scarce resource property binding post-evaluation optimisation
+ // and for testing memory usage in property var circular reference test
+ qmlRegisterType<ScarceResourceObject>("Qt.test", 1,0, "MyScarceResourceObject");
+
+ // Register the uncreatable base class
+ qmlRegisterRevision<MyRevisionedBaseClassRegistered,1>("Qt.test",1,1);
+ // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
+ qmlRegisterType<MyRevisionedSubclass>("Qt.test",1,0,"MyRevisionedSubclass");
+ // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
+ qmlRegisterType<MyRevisionedSubclass,1>("Qt.test",1,1,"MyRevisionedSubclass");
+
+ qmlRegisterExtendedType<QWidget,QWidgetDeclarativeUI>("Qt.test",1,0,"QWidget");
+ qmlRegisterType<QPlainTextEdit>("Qt.test",1,0,"QPlainTextEdit");
+
+ qRegisterMetaType<MyQmlObject::MyType>("MyQmlObject::MyType");
+
+ qmlRegisterModuleApi("Qt.test",1,0,script_api); // register (script) module API for an existing uri which contains elements
+ qmlRegisterModuleApi("Qt.test",1,0,qobject_api); // register (qobject) for an existing uri for which another module API was previously regd. Should replace!
+ qmlRegisterModuleApi("Qt.test.scriptApi",1,0,script_api); // register (script) module API for a uri which doesn't contain elements
+ qmlRegisterModuleApi("Qt.test.scriptApi",2,0,readonly_script_api); // register (script) module API for a uri which doesn't contain elements - will be made read-only
+ qmlRegisterModuleApi("Qt.test.qobjectApi",1,0,qobject_api); // register (qobject) module API for a uri which doesn't contain elements
+ qmlRegisterModuleApi("Qt.test.qobjectApi",1,3,qobject_api); // register (qobject) module API for a uri which doesn't contain elements, minor version set
+ qmlRegisterModuleApi("Qt.test.qobjectApi",2,0,qobject_api); // register (qobject) module API for a uri which doesn't contain elements, major version set
+ qmlRegisterModuleApi("Qt.test.qobjectApiParented",1,0,qobject_api_engine_parent); // register (parented qobject) module API for a uri which doesn't contain elements
+
+ qRegisterMetaType<MyQmlObject::MyType>("MyEnum2");
+ qRegisterMetaType<Qt::MouseButtons>("Qt::MouseButtons");
+
+ qmlRegisterType<CircularReferenceObject>("Qt.test", 1, 0, "CircularReferenceObject");
+ qmlRegisterType<CircularReferenceHandle>("Qt.test", 1, 0, "CircularReferenceHandle");
+
+ qmlRegisterType<MyDynamicCreationDestructionObject>("Qt.test", 1, 0, "MyDynamicCreationDestructionObject");
+ qmlRegisterType<WriteCounter>("Qt.test", 1, 0, "WriteCounter");
+
+ qmlRegisterType<MySequenceConversionObject>("Qt.test", 1, 0, "MySequenceConversionObject");
+}
+
+#include "testtypes.moc"
diff --git a/tests/auto/qml/qqmlecmascript/testtypes.h b/tests/auto/qml/qqmlecmascript/testtypes.h
new file mode 100644
index 0000000000..1d68e8ae13
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/testtypes.h
@@ -0,0 +1,1313 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef TESTTYPES_H
+#define TESTTYPES_H
+
+#include <QtCore/qobject.h>
+#include <QtQml/qqml.h>
+#include <QtQml/qqmlexpression.h>
+#include <QtCore/qpoint.h>
+#include <QtCore/qsize.h>
+#include <QtQml/qqmllist.h>
+#include <QtCore/qrect.h>
+#include <QtGui/qmatrix.h>
+#include <QtGui/qcolor.h>
+#include <QtGui/qvector3d.h>
+#include <QtGui/QPixmap>
+#include <QtCore/qdatetime.h>
+#include <QtQml/qjsvalue.h>
+#include <QtQml/qqmlscriptstring.h>
+#include <QtQml/qqmlcomponent.h>
+
+#include <private/qqmlengine_p.h>
+#include <private/qv8engine_p.h>
+
+class MyQmlAttachedObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int value READ value CONSTANT)
+ Q_PROPERTY(int value2 READ value2 WRITE setValue2 NOTIFY value2Changed)
+public:
+ MyQmlAttachedObject(QObject *parent) : QObject(parent), m_value2(0) {}
+
+ int value() const { return 19; }
+ int value2() const { return m_value2; }
+ void setValue2(int v) { if (m_value2 == v) return; m_value2 = v; emit value2Changed(); }
+
+ void emitMySignal() { emit mySignal(); }
+
+signals:
+ void value2Changed();
+ void mySignal();
+
+private:
+ int m_value2;
+};
+
+class MyQmlObject : public QObject
+{
+ Q_OBJECT
+ Q_ENUMS(MyEnum)
+ Q_ENUMS(MyEnum2)
+ Q_PROPERTY(int deleteOnSet READ deleteOnSet WRITE setDeleteOnSet)
+ Q_PROPERTY(bool trueProperty READ trueProperty CONSTANT)
+ Q_PROPERTY(bool falseProperty READ falseProperty CONSTANT)
+ Q_PROPERTY(int value READ value WRITE setValue)
+ Q_PROPERTY(int console READ console CONSTANT)
+ Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty NOTIFY stringChanged)
+ Q_PROPERTY(QUrl urlProperty READ urlProperty WRITE setUrlProperty NOTIFY urlChanged)
+ Q_PROPERTY(QObject *objectProperty READ objectProperty WRITE setObjectProperty NOTIFY objectChanged)
+ 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(int nonscriptable READ nonscriptable WRITE setNonscriptable SCRIPTABLE false)
+ Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty NOTIFY intChanged)
+
+public:
+ MyQmlObject(): myinvokableObject(0), m_methodCalled(false), m_methodIntCalled(false), m_object(0), m_value(0), m_resetProperty(13), m_intProperty(0) {}
+
+ enum MyEnum { EnumValue1 = 0, EnumValue2 = 1 };
+ enum MyEnum2 { EnumValue3 = 2, EnumValue4 = 3 };
+
+ bool trueProperty() const { return true; }
+ bool falseProperty() const { return false; }
+
+ QString stringProperty() const { return m_string; }
+ void setStringProperty(const QString &s)
+ {
+ if (s == m_string)
+ return;
+ m_string = s;
+ emit stringChanged();
+ }
+
+ QUrl urlProperty() const { return m_url; }
+ void setUrlProperty(const QUrl &url)
+ {
+ if (url == m_url)
+ return;
+ m_url = url;
+ emit urlChanged();
+ }
+
+ QObject *objectProperty() const { return m_object; }
+ void setObjectProperty(QObject *obj) {
+ if (obj == m_object)
+ return;
+ m_object = obj;
+ emit objectChanged();
+ }
+
+ QQmlListProperty<QObject> objectListProperty() { return QQmlListProperty<QObject>(this, m_objectQList); }
+
+ bool methodCalled() const { return m_methodCalled; }
+ bool methodIntCalled() const { return m_methodIntCalled; }
+
+ QString string() const { return m_string; }
+
+ static MyQmlAttachedObject *qmlAttachedProperties(QObject *o) {
+ return new MyQmlAttachedObject(o);
+ }
+
+ int deleteOnSet() const { return 1; }
+ void setDeleteOnSet(int v) { if(v) delete this; }
+
+ int value() const { return m_value; }
+ void setValue(int v) { m_value = v; }
+
+ int resettableProperty() const { return m_resetProperty; }
+ void setResettableProperty(int v) { m_resetProperty = v; }
+ void resetProperty() { m_resetProperty = 13; }
+
+ QRegExp regExp() { return m_regExp; }
+ void setRegExp(const QRegExp &regExp) { m_regExp = regExp; }
+
+ int console() const { return 11; }
+
+ int nonscriptable() const { return 0; }
+ void setNonscriptable(int) {}
+
+ MyQmlObject *myinvokableObject;
+ Q_INVOKABLE MyQmlObject *returnme() { return this; }
+
+ struct MyType {
+ int value;
+ };
+ QVariant variant() const { return m_variant; }
+ QJSValue qjsvalue() const { return m_qjsvalue; }
+
+ int intProperty() const { return m_intProperty; }
+ void setIntProperty(int i) { m_intProperty = i; emit intChanged(); }
+
+signals:
+ void basicSignal();
+ void argumentSignal(int a, QString b, qreal c, MyEnum2 d, Qt::MouseButtons e);
+ void unnamedArgumentSignal(int a, qreal, QString c);
+ void stringChanged();
+ void urlChanged();
+ void objectChanged();
+ void anotherBasicSignal();
+ void thirdBasicSignal();
+ void signalWithUnknownType(const MyQmlObject::MyType &arg);
+ void signalWithVariant(const QVariant &arg);
+ void signalWithQJSValue(const QJSValue &arg);
+ void signalWithGlobalName(int parseInt);
+ void intChanged();
+
+public slots:
+ void deleteMe() { delete this; }
+ void methodNoArgs() { m_methodCalled = true; }
+ void method(int a) { if(a == 163) m_methodIntCalled = true; }
+ void setString(const QString &s) { m_string = s; }
+ void myinvokable(MyQmlObject *o) { myinvokableObject = o; }
+ void variantMethod(const QVariant &v) { m_variant = v; }
+ void qjsvalueMethod(const QJSValue &v) { m_qjsvalue = v; }
+ void v8function(QQmlV8Function*);
+
+private:
+ friend class tst_qqmlecmascript;
+ bool m_methodCalled;
+ bool m_methodIntCalled;
+
+ QObject *m_object;
+ QString m_string;
+ QUrl m_url;
+ QList<QObject *> m_objectQList;
+ int m_value;
+ int m_resetProperty;
+ QRegExp m_regExp;
+ QVariant m_variant;
+ QJSValue m_qjsvalue;
+ int m_intProperty;
+};
+
+QML_DECLARE_TYPEINFO(MyQmlObject, QML_HAS_ATTACHED_PROPERTIES)
+
+class MyQmlContainer : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QQmlListProperty<MyQmlObject> children READ children CONSTANT)
+public:
+ MyQmlContainer() {}
+
+ QQmlListProperty<MyQmlObject> children() { return QQmlListProperty<MyQmlObject>(this, m_children); }
+
+private:
+ QList<MyQmlObject*> m_children;
+};
+
+
+class MyExpression : public QQmlExpression
+{
+ Q_OBJECT
+public:
+ MyExpression(QQmlContext *ctxt, const QString &expr)
+ : QQmlExpression(ctxt, 0, expr), changed(false)
+ {
+ QObject::connect(this, SIGNAL(valueChanged()), this, SLOT(expressionValueChanged()));
+ setNotifyOnValueChanged(true);
+ }
+
+ bool changed;
+
+public slots:
+ void expressionValueChanged() {
+ changed = true;
+ }
+};
+
+
+class MyDefaultObject1 : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int horseLegs READ horseLegs CONSTANT)
+ Q_PROPERTY(int antLegs READ antLegs CONSTANT)
+ Q_PROPERTY(int emuLegs READ emuLegs CONSTANT)
+public:
+ int horseLegs() const { return 4; }
+ int antLegs() const { return 6; }
+ int emuLegs() const { return 2; }
+};
+
+class MyDefaultObject3 : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int antLegs READ antLegs CONSTANT)
+ Q_PROPERTY(int humanLegs READ humanLegs CONSTANT)
+public:
+ int antLegs() const { return 7; } // Mutant
+ int humanLegs() const { return 2; }
+ int millipedeLegs() const { return 1000; }
+};
+
+class MyDeferredObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged)
+ Q_PROPERTY(QObject *objectProperty READ objectProperty WRITE setObjectProperty)
+ Q_PROPERTY(QObject *objectProperty2 READ objectProperty2 WRITE setObjectProperty2)
+ Q_CLASSINFO("DeferredPropertyNames", "value,objectProperty,objectProperty2")
+
+public:
+ MyDeferredObject() : m_value(0), m_object(0), m_object2(0) {}
+
+ int value() const { return m_value; }
+ void setValue(int v) { m_value = v; emit valueChanged(); }
+
+ QObject *objectProperty() const { return m_object; }
+ void setObjectProperty(QObject *obj) { m_object = obj; }
+
+ QObject *objectProperty2() const { return m_object2; }
+ void setObjectProperty2(QObject *obj) { m_object2 = obj; }
+
+signals:
+ void valueChanged();
+
+private:
+ int m_value;
+ QObject *m_object;
+ QObject *m_object2;
+};
+
+class MyBaseExtendedObject : public QObject
+{
+Q_OBJECT
+Q_PROPERTY(int baseProperty READ baseProperty WRITE setBaseProperty)
+public:
+ MyBaseExtendedObject() : m_value(0) {}
+
+ int baseProperty() const { return m_value; }
+ void setBaseProperty(int v) { m_value = v; }
+
+private:
+ int m_value;
+};
+
+class MyExtendedObject : public MyBaseExtendedObject
+{
+Q_OBJECT
+Q_PROPERTY(int coreProperty READ coreProperty WRITE setCoreProperty)
+public:
+ MyExtendedObject() : m_value(0) {}
+
+ int coreProperty() const { return m_value; }
+ void setCoreProperty(int v) { m_value = v; }
+
+private:
+ int m_value;
+};
+
+class MyTypeObject : public QObject
+{
+ Q_OBJECT
+ Q_ENUMS(MyEnum)
+ Q_FLAGS(MyFlags)
+
+ Q_PROPERTY(QString id READ id WRITE setId)
+ Q_PROPERTY(QObject *objectProperty READ objectProperty WRITE setObjectProperty)
+ Q_PROPERTY(QQmlComponent *componentProperty READ componentProperty WRITE setComponentProperty)
+ Q_PROPERTY(MyFlags flagProperty READ flagProperty WRITE setFlagProperty)
+ Q_PROPERTY(MyEnum enumProperty READ enumProperty WRITE setEnumProperty)
+ Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty)
+ Q_PROPERTY(uint uintProperty READ uintProperty WRITE setUintProperty)
+ Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty)
+ Q_PROPERTY(qreal realProperty READ realProperty WRITE setRealProperty)
+ Q_PROPERTY(double doubleProperty READ doubleProperty WRITE setDoubleProperty)
+ Q_PROPERTY(float floatProperty READ floatProperty WRITE setFloatProperty)
+ Q_PROPERTY(QColor colorProperty READ colorProperty WRITE setColorProperty)
+ Q_PROPERTY(QDate dateProperty READ dateProperty WRITE setDateProperty)
+ Q_PROPERTY(QTime timeProperty READ timeProperty WRITE setTimeProperty)
+ Q_PROPERTY(QDateTime dateTimeProperty READ dateTimeProperty WRITE setDateTimeProperty)
+ Q_PROPERTY(QPoint pointProperty READ pointProperty WRITE setPointProperty)
+ Q_PROPERTY(QPointF pointFProperty READ pointFProperty WRITE setPointFProperty)
+ Q_PROPERTY(QSize sizeProperty READ sizeProperty WRITE setSizeProperty)
+ Q_PROPERTY(QSizeF sizeFProperty READ sizeFProperty WRITE setSizeFProperty)
+ Q_PROPERTY(QRect rectProperty READ rectProperty WRITE setRectProperty NOTIFY rectPropertyChanged)
+ Q_PROPERTY(QRect rectProperty2 READ rectProperty2 WRITE setRectProperty2)
+ Q_PROPERTY(QRectF rectFProperty READ rectFProperty WRITE setRectFProperty)
+ Q_PROPERTY(bool boolProperty READ boolProperty WRITE setBoolProperty)
+ Q_PROPERTY(QVariant variantProperty READ variantProperty WRITE setVariantProperty)
+ Q_PROPERTY(QVector3D vectorProperty READ vectorProperty WRITE setVectorProperty)
+ Q_PROPERTY(QUrl urlProperty READ urlProperty WRITE setUrlProperty)
+
+ Q_PROPERTY(QQmlScriptString scriptProperty READ scriptProperty WRITE setScriptProperty)
+
+public:
+ MyTypeObject()
+ : objectPropertyValue(0), componentPropertyValue(0) {}
+
+ QString idValue;
+ QString id() const {
+ return idValue;
+ }
+ void setId(const QString &v) {
+ idValue = v;
+ }
+
+ QObject *objectPropertyValue;
+ QObject *objectProperty() const {
+ return objectPropertyValue;
+ }
+ void setObjectProperty(QObject *v) {
+ objectPropertyValue = v;
+ }
+
+ QQmlComponent *componentPropertyValue;
+ QQmlComponent *componentProperty() const {
+ return componentPropertyValue;
+ }
+ void setComponentProperty(QQmlComponent *v) {
+ componentPropertyValue = v;
+ }
+
+ enum MyFlag { FlagVal1 = 0x01, FlagVal2 = 0x02, FlagVal3 = 0x04 };
+ Q_DECLARE_FLAGS(MyFlags, MyFlag)
+ MyFlags flagPropertyValue;
+ MyFlags flagProperty() const {
+ return flagPropertyValue;
+ }
+ void setFlagProperty(MyFlags v) {
+ flagPropertyValue = v;
+ }
+
+ enum MyEnum { EnumVal1, EnumVal2 };
+ MyEnum enumPropertyValue;
+ MyEnum enumProperty() const {
+ return enumPropertyValue;
+ }
+ void setEnumProperty(MyEnum v) {
+ enumPropertyValue = v;
+ }
+
+ QString stringPropertyValue;
+ QString stringProperty() const {
+ return stringPropertyValue;
+ }
+ void setStringProperty(const QString &v) {
+ stringPropertyValue = v;
+ }
+
+ uint uintPropertyValue;
+ uint uintProperty() const {
+ return uintPropertyValue;
+ }
+ void setUintProperty(const uint &v) {
+ uintPropertyValue = v;
+ }
+
+ int intPropertyValue;
+ int intProperty() const {
+ return intPropertyValue;
+ }
+ void setIntProperty(const int &v) {
+ intPropertyValue = v;
+ }
+
+ qreal realPropertyValue;
+ qreal realProperty() const {
+ return realPropertyValue;
+ }
+ void setRealProperty(const qreal &v) {
+ realPropertyValue = v;
+ }
+
+ double doublePropertyValue;
+ double doubleProperty() const {
+ return doublePropertyValue;
+ }
+ void setDoubleProperty(const double &v) {
+ doublePropertyValue = v;
+ }
+
+ float floatPropertyValue;
+ float floatProperty() const {
+ return floatPropertyValue;
+ }
+ void setFloatProperty(const float &v) {
+ floatPropertyValue = v;
+ }
+
+ QColor colorPropertyValue;
+ QColor colorProperty() const {
+ return colorPropertyValue;
+ }
+ void setColorProperty(const QColor &v) {
+ colorPropertyValue = v;
+ }
+
+ QDate datePropertyValue;
+ QDate dateProperty() const {
+ return datePropertyValue;
+ }
+ void setDateProperty(const QDate &v) {
+ datePropertyValue = v;
+ }
+
+ QTime timePropertyValue;
+ QTime timeProperty() const {
+ return timePropertyValue;
+ }
+ void setTimeProperty(const QTime &v) {
+ timePropertyValue = v;
+ }
+
+ QDateTime dateTimePropertyValue;
+ QDateTime dateTimeProperty() const {
+ return dateTimePropertyValue;
+ }
+ void setDateTimeProperty(const QDateTime &v) {
+ dateTimePropertyValue = v;
+ }
+
+ QPoint pointPropertyValue;
+ QPoint pointProperty() const {
+ return pointPropertyValue;
+ }
+ void setPointProperty(const QPoint &v) {
+ pointPropertyValue = v;
+ }
+
+ QPointF pointFPropertyValue;
+ QPointF pointFProperty() const {
+ return pointFPropertyValue;
+ }
+ void setPointFProperty(const QPointF &v) {
+ pointFPropertyValue = v;
+ }
+
+ QSize sizePropertyValue;
+ QSize sizeProperty() const {
+ return sizePropertyValue;
+ }
+ void setSizeProperty(const QSize &v) {
+ sizePropertyValue = v;
+ }
+
+ QSizeF sizeFPropertyValue;
+ QSizeF sizeFProperty() const {
+ return sizeFPropertyValue;
+ }
+ void setSizeFProperty(const QSizeF &v) {
+ sizeFPropertyValue = v;
+ }
+
+ QRect rectPropertyValue;
+ QRect rectProperty() const {
+ return rectPropertyValue;
+ }
+ void setRectProperty(const QRect &v) {
+ rectPropertyValue = v;
+ emit rectPropertyChanged();
+ }
+
+ QRect rectPropertyValue2;
+ QRect rectProperty2() const {
+ return rectPropertyValue2;
+ }
+ void setRectProperty2(const QRect &v) {
+ rectPropertyValue2 = v;
+ }
+
+ QRectF rectFPropertyValue;
+ QRectF rectFProperty() const {
+ return rectFPropertyValue;
+ }
+ void setRectFProperty(const QRectF &v) {
+ rectFPropertyValue = v;
+ }
+
+ bool boolPropertyValue;
+ bool boolProperty() const {
+ return boolPropertyValue;
+ }
+ void setBoolProperty(const bool &v) {
+ boolPropertyValue = v;
+ }
+
+ QVariant variantPropertyValue;
+ QVariant variantProperty() const {
+ return variantPropertyValue;
+ }
+ void setVariantProperty(const QVariant &v) {
+ variantPropertyValue = v;
+ }
+
+ QVector3D vectorPropertyValue;
+ QVector3D vectorProperty() const {
+ return vectorPropertyValue;
+ }
+ void setVectorProperty(const QVector3D &v) {
+ vectorPropertyValue = v;
+ }
+
+ QUrl urlPropertyValue;
+ QUrl urlProperty() const {
+ return urlPropertyValue;
+ }
+ void setUrlProperty(const QUrl &v) {
+ urlPropertyValue = v;
+ }
+
+ QQmlScriptString scriptPropertyValue;
+ QQmlScriptString scriptProperty() const {
+ return scriptPropertyValue;
+ }
+ void setScriptProperty(const QQmlScriptString &v) {
+ scriptPropertyValue = v;
+ }
+
+ void doAction() { emit action(); }
+signals:
+ void action();
+ void rectPropertyChanged();
+};
+Q_DECLARE_OPERATORS_FOR_FLAGS(MyTypeObject::MyFlags)
+
+class MyDerivedObject : public MyTypeObject
+{
+ Q_OBJECT
+public:
+ Q_INVOKABLE bool intProperty() const {
+ return true;
+ }
+};
+
+Q_DECLARE_METATYPE(QJSValue);
+class MyInvokableBaseObject : public QObject
+{
+ Q_OBJECT
+public:
+ inline ~MyInvokableBaseObject() = 0;
+
+ Q_INVOKABLE inline void method_inherited(int a);
+ Q_INVOKABLE inline void method_overload();
+};
+
+class MyInvokableObject : public MyInvokableBaseObject
+{
+ Q_OBJECT
+ Q_ENUMS(TestEnum)
+public:
+ enum TestEnum { EnumValue1, EnumValue2 };
+ MyInvokableObject() { reset(); }
+
+ int invoked() const { return m_invoked; }
+ bool error() const { return m_invokedError; }
+ const QVariantList &actuals() const { return m_actuals; }
+ void reset() { m_invoked = -1; m_invokedError = false; m_actuals.clear(); }
+
+ Q_INVOKABLE QPointF method_get_QPointF() { return QPointF(99.3, -10.2); }
+ Q_INVOKABLE QPoint method_get_QPoint() { return QPoint(9, 12); }
+
+ Q_INVOKABLE void method_NoArgs() { invoke(0); }
+ Q_INVOKABLE int method_NoArgs_int() { invoke(1); return 6; }
+ Q_INVOKABLE qreal method_NoArgs_real() { invoke(2); return 19.75; }
+ Q_INVOKABLE QPointF method_NoArgs_QPointF() { invoke(3); return QPointF(123, 4.5); }
+ Q_INVOKABLE QObject *method_NoArgs_QObject() { invoke(4); return this; }
+ Q_INVOKABLE MyInvokableObject *method_NoArgs_unknown() { invoke(5); return this; }
+ Q_INVOKABLE QJSValue method_NoArgs_QScriptValue() { invoke(6); return QJSValue("Hello world"); }
+ Q_INVOKABLE QVariant method_NoArgs_QVariant() { invoke(7); return QVariant("QML rocks"); }
+
+ Q_INVOKABLE void method_int(int a) { invoke(8); m_actuals << a; }
+ Q_INVOKABLE void method_intint(int a, int b) { invoke(9); m_actuals << a << b; }
+ Q_INVOKABLE void method_real(qreal a) { invoke(10); m_actuals << a; }
+ Q_INVOKABLE void method_QString(QString a) { invoke(11); m_actuals << a; }
+ Q_INVOKABLE void method_QPointF(QPointF a) { invoke(12); m_actuals << a; }
+ Q_INVOKABLE void method_QObject(QObject *a) { invoke(13); m_actuals << qVariantFromValue(a); }
+ Q_INVOKABLE void method_QScriptValue(QJSValue a) { invoke(14); m_actuals << qVariantFromValue(a); }
+ Q_INVOKABLE void method_intQScriptValue(int a, QJSValue b) { invoke(15); m_actuals << a << qVariantFromValue(b); }
+
+ Q_INVOKABLE void method_overload(int a) { invoke(16); m_actuals << a; }
+ Q_INVOKABLE void method_overload(int a, int b) { invoke(17); m_actuals << a << b; }
+ Q_INVOKABLE void method_overload(QString a) { invoke(18); m_actuals << a; }
+
+ Q_INVOKABLE void method_with_enum(TestEnum e) { invoke(19); m_actuals << (int)e; }
+
+ Q_INVOKABLE int method_default(int a, int b = 19) { invoke(20); m_actuals << a << b; return b; }
+
+ Q_INVOKABLE void method_QVariant(QVariant a, QVariant b = QVariant()) { invoke(21); m_actuals << a << b; }
+
+private:
+ friend class MyInvokableBaseObject;
+ void invoke(int idx) { if (m_invoked != -1) m_invokedError = true; m_invoked = idx;}
+ int m_invoked;
+ bool m_invokedError;
+ QVariantList m_actuals;
+};
+
+MyInvokableBaseObject::~MyInvokableBaseObject() {}
+
+void MyInvokableBaseObject::method_inherited(int a)
+{
+ static_cast<MyInvokableObject *>(this)->invoke(-3);
+ static_cast<MyInvokableObject *>(this)->m_actuals << a;
+}
+
+// This is a hidden overload of the MyInvokableObject::method_overload() method
+void MyInvokableBaseObject::method_overload()
+{
+ static_cast<MyInvokableObject *>(this)->invoke(-2);
+}
+
+class NumberAssignment : public QObject
+{
+ Q_OBJECT
+public:
+ Q_PROPERTY(qreal test1 READ test1 WRITE setTest1)
+ qreal _test1;
+ qreal test1() const { return _test1; }
+ void setTest1(qreal v) { _test1 = v; }
+
+ Q_PROPERTY(qreal test2 READ test2 WRITE setTest2)
+ qreal _test2;
+ qreal test2() const { return _test2; }
+ void setTest2(qreal v) { _test2 = v; }
+
+ Q_PROPERTY(qreal test3 READ test3 WRITE setTest3)
+ qreal _test3;
+ qreal test3() const { return _test3; }
+ void setTest3(qreal v) { _test3 = v; }
+
+ Q_PROPERTY(qreal test4 READ test4 WRITE setTest4)
+ qreal _test4;
+ qreal test4() const { return _test4; }
+ void setTest4(qreal v) { _test4 = v; }
+
+ Q_PROPERTY(int test5 READ test5 WRITE setTest5)
+ int _test5;
+ int test5() const { return _test5; }
+ void setTest5(int v) { _test5 = v; }
+
+ Q_PROPERTY(int test6 READ test6 WRITE setTest6)
+ int _test6;
+ int test6() const { return _test6; }
+ void setTest6(int v) { _test6 = v; }
+
+ Q_PROPERTY(int test7 READ test7 WRITE setTest7)
+ int _test7;
+ int test7() const { return _test7; }
+ void setTest7(int v) { _test7 = v; }
+
+ Q_PROPERTY(int test8 READ test8 WRITE setTest8)
+ int _test8;
+ int test8() const { return _test8; }
+ void setTest8(int v) { _test8 = v; }
+
+ Q_PROPERTY(unsigned int test9 READ test9 WRITE setTest9)
+ unsigned int _test9;
+ unsigned int test9() const { return _test9; }
+ void setTest9(unsigned int v) { _test9 = v; }
+
+ Q_PROPERTY(unsigned int test10 READ test10 WRITE setTest10)
+ unsigned int _test10;
+ unsigned int test10() const { return _test10; }
+ void setTest10(unsigned int v) { _test10 = v; }
+
+ Q_PROPERTY(unsigned int test11 READ test11 WRITE setTest11)
+ unsigned int _test11;
+ unsigned int test11() const { return _test11; }
+ void setTest11(unsigned int v) { _test11 = v; }
+
+ Q_PROPERTY(unsigned int test12 READ test12 WRITE setTest12)
+ unsigned int _test12;
+ unsigned int test12() const { return _test12; }
+ void setTest12(unsigned int v) { _test12 = v; }
+};
+
+class DefaultPropertyExtendedObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QObject *firstProperty READ firstProperty WRITE setFirstProperty)
+ Q_PROPERTY(QObject *secondProperty READ secondProperty WRITE setSecondProperty)
+public:
+ DefaultPropertyExtendedObject(QObject *parent = 0) : QObject(parent), m_firstProperty(0), m_secondProperty(0) {}
+
+ QObject *firstProperty() const { return m_firstProperty; }
+ QObject *secondProperty() const { return m_secondProperty; }
+ void setFirstProperty(QObject *property) { m_firstProperty = property; }
+ void setSecondProperty(QObject *property) { m_secondProperty = property; }
+private:
+ QObject* m_firstProperty;
+ QObject* m_secondProperty;
+};
+
+class OverrideDefaultPropertyObject : public DefaultPropertyExtendedObject
+{
+ Q_OBJECT
+ Q_CLASSINFO("DefaultProperty", "secondProperty")
+public:
+ OverrideDefaultPropertyObject() {}
+};
+
+class MyRevisionedBaseClassRegistered : public QObject
+{
+Q_OBJECT
+ Q_PROPERTY(qreal propA READ propA WRITE setPropA NOTIFY propAChanged)
+ Q_PROPERTY(qreal propB READ propB WRITE setPropB NOTIFY propBChanged REVISION 1)
+
+public:
+ MyRevisionedBaseClassRegistered() : m_pa(1), m_pb(2) {}
+
+ qreal propA() const { return m_pa; }
+ void setPropA(qreal p) {
+ if (p != m_pa) {
+ m_pa = p;
+ emit propAChanged();
+ }
+ }
+ qreal propB() const { return m_pb; }
+ void setPropB(qreal p) {
+ if (p != m_pb) {
+ m_pb = p;
+ emit propBChanged();
+ }
+ }
+
+ Q_INVOKABLE void methodA() { }
+ Q_INVOKABLE Q_REVISION(1) void methodB() { }
+
+signals:
+ void propAChanged();
+ void propBChanged();
+
+ void signalA();
+ Q_REVISION(1) void signalB();
+
+protected:
+ qreal m_pa;
+ qreal m_pb;
+};
+
+class MyRevisionedBaseClassUnregistered : public MyRevisionedBaseClassRegistered
+{
+Q_OBJECT
+ Q_PROPERTY(qreal propC READ propC WRITE setPropC NOTIFY propCChanged)
+ Q_PROPERTY(qreal propD READ propD WRITE setPropD NOTIFY propDChanged REVISION 1)
+
+public:
+ MyRevisionedBaseClassUnregistered() : m_pc(1), m_pd(2) {}
+
+ qreal propC() const { return m_pc; }
+ void setPropC(qreal p) {
+ if (p != m_pc) {
+ m_pc = p;
+ emit propCChanged();
+ }
+ }
+ qreal propD() const { return m_pd; }
+ void setPropD(qreal p) {
+ if (p != m_pd) {
+ m_pd = p;
+ emit propDChanged();
+ }
+ }
+
+ Q_INVOKABLE void methodC() { }
+ Q_INVOKABLE Q_REVISION(1) void methodD() { }
+
+signals:
+ void propCChanged();
+ void propDChanged();
+
+ void signalC();
+ Q_REVISION(1) void signalD();
+
+protected:
+ qreal m_pc;
+ qreal m_pd;
+};
+
+class MyRevisionedClass : public MyRevisionedBaseClassUnregistered
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal prop1 READ prop1 WRITE setProp1 NOTIFY prop1Changed)
+ Q_PROPERTY(qreal prop2 READ prop2 WRITE setProp2 NOTIFY prop2Changed REVISION 1)
+
+public:
+ MyRevisionedClass() {}
+
+ qreal prop1() const { return m_p1; }
+ void setProp1(qreal p) {
+ if (p != m_p1) {
+ m_p1 = p;
+ emit prop1Changed();
+ }
+ }
+ qreal prop2() const { return m_p2; }
+ void setProp2(qreal p) {
+ if (p != m_p2) {
+ m_p2 = p;
+ emit prop2Changed();
+ }
+ }
+
+ Q_INVOKABLE void method1() { }
+ Q_INVOKABLE Q_REVISION(1) void method2() { }
+
+signals:
+ void prop1Changed();
+ void prop2Changed();
+
+ void signal1();
+ Q_REVISION(1) void signal2();
+
+protected:
+ qreal m_p1;
+ qreal m_p2;
+};
+
+class MyRevisionedSubclass : public MyRevisionedClass
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal prop3 READ prop3 WRITE setProp3 NOTIFY prop3Changed)
+ Q_PROPERTY(qreal prop4 READ prop4 WRITE setProp4 NOTIFY prop4Changed REVISION 1)
+
+public:
+ MyRevisionedSubclass() : m_p3(3), m_p4(4) {}
+
+ qreal prop3() const { return m_p3; }
+ void setProp3(qreal p) {
+ if (p != m_p3) {
+ m_p3 = p;
+ emit prop3Changed();
+ }
+ }
+ qreal prop4() const { return m_p4; }
+ void setProp4(qreal p) {
+ if (p != m_p4) {
+ m_p4 = p;
+ emit prop4Changed();
+ }
+ }
+
+ Q_INVOKABLE void method3() { }
+ Q_INVOKABLE Q_REVISION(1) void method4() { }
+
+signals:
+ void prop3Changed();
+ void prop4Changed();
+
+ void signal3();
+ Q_REVISION(1) void signal4();
+
+protected:
+ qreal m_p3;
+ qreal m_p4;
+};
+
+QML_DECLARE_TYPE(MyRevisionedBaseClassRegistered)
+QML_DECLARE_TYPE(MyRevisionedBaseClassUnregistered)
+QML_DECLARE_TYPE(MyRevisionedClass)
+QML_DECLARE_TYPE(MyRevisionedSubclass)
+Q_DECLARE_METATYPE(MyQmlObject::MyType)
+
+
+class ScarceResourceObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QPixmap scarceResource READ scarceResource WRITE setScarceResource NOTIFY scarceResourceChanged)
+public:
+ ScarceResourceObject(QObject *parent = 0) : QObject(parent), m_value(100, 100) { m_value.fill(Qt::blue); }
+ ~ScarceResourceObject() {}
+
+ QPixmap scarceResource() const { return m_value; }
+ void setScarceResource(QPixmap v) { m_value = v; emit scarceResourceChanged(); }
+
+ bool scarceResourceIsDetached() const { return m_value.isDetached(); }
+
+ // this particular one returns a new one each time
+ // this means that every Scarce Resource Copy will
+ // consume resources (so that we can track disposal
+ // of v8 handles with circular references).
+ Q_INVOKABLE QPixmap newScarceResource() const
+ {
+ QPixmap retn(800, 600);
+ retn.fill(QColor(100, 110, 120, 45));
+ return retn;
+ }
+
+signals:
+ void scarceResourceChanged();
+
+private:
+ QPixmap m_value;
+};
+QML_DECLARE_TYPE(ScarceResourceObject)
+
+class testQObjectApi : public QObject
+{
+ Q_OBJECT
+ Q_ENUMS(MyEnum)
+ Q_PROPERTY (int qobjectTestProperty READ qobjectTestProperty NOTIFY qobjectTestPropertyChanged)
+ Q_PROPERTY (int qobjectTestWritableProperty READ qobjectTestWritableProperty WRITE setQObjectTestWritableProperty NOTIFY qobjectTestWritablePropertyChanged)
+
+public:
+ testQObjectApi(QObject* parent = 0)
+ : QObject(parent), m_testProperty(0), m_testWritableProperty(0), m_methodCallCount(0)
+ {
+ }
+
+ ~testQObjectApi() {}
+
+ enum MyEnum { EnumValue1 = 25, EnumValue2 = 42 };
+ Q_INVOKABLE int qobjectEnumTestMethod(MyEnum val) { return (static_cast<int>(val) + 5); }
+ Q_INVOKABLE int qobjectTestMethod(int increment = 1) { m_methodCallCount += increment; return m_methodCallCount; }
+
+ int qobjectTestProperty() const { return m_testProperty; }
+ void setQObjectTestProperty(int tp) { m_testProperty = tp; emit qobjectTestPropertyChanged(tp); }
+
+ int qobjectTestWritableProperty() const { return m_testWritableProperty; }
+ void setQObjectTestWritableProperty(int tp) { m_testWritableProperty = tp; emit qobjectTestWritablePropertyChanged(tp); }
+
+signals:
+ void qobjectTestPropertyChanged(int testProperty);
+ void qobjectTestWritablePropertyChanged(int testWritableProperty);
+
+private:
+ int m_testProperty;
+ int m_testWritableProperty;
+ int m_methodCallCount;
+};
+
+class CircularReferenceObject : public QObject,
+ public QV8GCCallback::Node
+{
+ Q_OBJECT
+
+public:
+ CircularReferenceObject(QObject *parent = 0)
+ : QObject(parent), QV8GCCallback::Node(callback), m_referenced(0), m_dtorCount(0)
+ {
+ QV8GCCallback::addGcCallbackNode(this);
+ }
+
+ ~CircularReferenceObject()
+ {
+ if (m_dtorCount) *m_dtorCount = *m_dtorCount + 1;
+ }
+
+ Q_INVOKABLE void setDtorCount(int *dtorCount)
+ {
+ m_dtorCount = dtorCount;
+ }
+
+ Q_INVOKABLE CircularReferenceObject *generate(QObject *parent = 0)
+ {
+ CircularReferenceObject *retn = new CircularReferenceObject(parent);
+ retn->m_dtorCount = m_dtorCount;
+ retn->m_engine = m_engine;
+ return retn;
+ }
+
+ Q_INVOKABLE void addReference(QObject *other)
+ {
+ m_referenced = other;
+ }
+
+ static void callback(QV8GCCallback::Node *n)
+ {
+ CircularReferenceObject *cro = static_cast<CircularReferenceObject*>(n);
+ if (cro->m_referenced) {
+ cro->m_engine->addRelationshipForGC(cro, cro->m_referenced);
+ }
+ }
+
+ void setEngine(QQmlEngine* declarativeEngine)
+ {
+ m_engine = QQmlEnginePrivate::get(declarativeEngine)->v8engine();
+ }
+
+private:
+ QObject *m_referenced;
+ int *m_dtorCount;
+ QV8Engine* m_engine;
+};
+Q_DECLARE_METATYPE(CircularReferenceObject*)
+
+class CircularReferenceHandle : public QObject,
+ public QV8GCCallback::Node
+{
+ Q_OBJECT
+
+public:
+ CircularReferenceHandle(QObject *parent = 0)
+ : QObject(parent), QV8GCCallback::Node(gccallback), m_dtorCount(0), m_engine(0)
+ {
+ QV8GCCallback::addGcCallbackNode(this);
+ }
+
+ ~CircularReferenceHandle()
+ {
+ if (m_dtorCount) *m_dtorCount = *m_dtorCount + 1;
+ }
+
+ Q_INVOKABLE void setDtorCount(int *dtorCount)
+ {
+ m_dtorCount = dtorCount;
+ }
+
+ Q_INVOKABLE CircularReferenceHandle *generate(QObject *parent = 0)
+ {
+ CircularReferenceHandle *retn = new CircularReferenceHandle(parent);
+ retn->m_dtorCount = m_dtorCount;
+ retn->m_engine = m_engine;
+ return retn;
+ }
+
+ Q_INVOKABLE void addReference(v8::Persistent<v8::Value> handle)
+ {
+ m_referenced = qPersistentNew(handle);
+ m_referenced.MakeWeak(static_cast<void*>(this), wrcallback);
+ }
+
+ static void wrcallback(v8::Persistent<v8::Value> handle, void *params)
+ {
+ CircularReferenceHandle *crh = static_cast<CircularReferenceHandle*>(params);
+ qPersistentDispose(handle);
+ crh->m_referenced.Clear();
+ }
+
+ static void gccallback(QV8GCCallback::Node *n)
+ {
+ CircularReferenceHandle *crh = static_cast<CircularReferenceHandle*>(n);
+ crh->m_engine->addRelationshipForGC(crh, crh->m_referenced);
+ }
+
+ void setEngine(QQmlEngine* declarativeEngine)
+ {
+ m_engine = QQmlEnginePrivate::get(declarativeEngine)->v8engine();
+ }
+
+private:
+ v8::Persistent<v8::Value> m_referenced;
+ int *m_dtorCount;
+ QV8Engine* m_engine;
+};
+Q_DECLARE_METATYPE(CircularReferenceHandle*)
+
+class MyDynamicCreationDestructionObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY (int intProperty READ intProperty WRITE setIntProperty NOTIFY intPropertyChanged)
+
+public:
+ MyDynamicCreationDestructionObject(QObject *parent = 0) : QObject(parent), m_intProperty(0), m_dtorCount(0)
+ {
+ }
+
+ ~MyDynamicCreationDestructionObject()
+ {
+ if (m_dtorCount) {
+ (*m_dtorCount)++;
+ }
+ }
+
+ int intProperty() const { return m_intProperty; }
+ void setIntProperty(int val) { m_intProperty = val; emit intPropertyChanged(); }
+
+ Q_INVOKABLE MyDynamicCreationDestructionObject *createNew()
+ {
+ // no parent == ownership transfers to JS; same dtor counter.
+ MyDynamicCreationDestructionObject *retn = new MyDynamicCreationDestructionObject;
+ retn->setDtorCount(m_dtorCount);
+ return retn;
+ }
+
+ void setDtorCount(int *dtorCount)
+ {
+ m_dtorCount = dtorCount;
+ }
+
+signals:
+ void intPropertyChanged();
+
+private:
+ int m_intProperty;
+ int *m_dtorCount;
+};
+
+class WriteCounter : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int value READ value WRITE setValue);
+public:
+ WriteCounter() : m_value(0), m_count(0) {}
+
+ int value() const { return m_value; }
+ void setValue(int v) { m_value = v; ++m_count; }
+
+ int count() const { return m_count; }
+
+private:
+ int m_value;
+ int m_count;
+};
+
+class MySequenceConversionObject : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY (QList<int> intListProperty READ intListProperty WRITE setIntListProperty NOTIFY intListPropertyChanged)
+ Q_PROPERTY (QList<int> intListProperty2 READ intListProperty2 WRITE setIntListProperty2 NOTIFY intListProperty2Changed)
+ Q_PROPERTY (QList<qreal> qrealListProperty READ qrealListProperty WRITE setQrealListProperty NOTIFY qrealListPropertyChanged)
+ Q_PROPERTY (QList<bool> boolListProperty READ boolListProperty WRITE setBoolListProperty NOTIFY boolListPropertyChanged)
+ Q_PROPERTY (QList<QString> stringListProperty READ stringListProperty WRITE setStringListProperty NOTIFY stringListPropertyChanged)
+ Q_PROPERTY (QList<QUrl> urlListProperty READ urlListProperty WRITE setUrlListProperty NOTIFY urlListPropertyChanged)
+ Q_PROPERTY (QStringList qstringListProperty READ qstringListProperty WRITE setQStringListProperty NOTIFY qstringListPropertyChanged)
+
+ Q_PROPERTY (QList<QPoint> pointListProperty READ pointListProperty WRITE setPointListProperty NOTIFY pointListPropertyChanged)
+ Q_PROPERTY (QList<QVariant> variantListProperty READ variantListProperty WRITE setVariantListProperty NOTIFY variantListPropertyChanged)
+
+ Q_PROPERTY (qint32 maxIndex READ maxIndex CONSTANT)
+ Q_PROPERTY (quint32 tooBigIndex READ tooBigIndex CONSTANT)
+ Q_PROPERTY (qint32 negativeIndex READ negativeIndex CONSTANT)
+
+public:
+ MySequenceConversionObject()
+ {
+ m_intList << 1 << 2 << 3 << 4;
+ m_intList2 << 1 << 2 << 3 << 4;
+ m_qrealList << 1.1 << 2.2 << 3.3 << 4.4;
+ m_boolList << true << false << true << false;
+ m_stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
+ m_urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com");
+ m_qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
+
+ m_pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6);
+ m_variantList << QVariant(QLatin1String("one")) << QVariant(true) << QVariant(3);
+ }
+
+ ~MySequenceConversionObject() {}
+
+ qint32 maxIndex() const
+ {
+ return INT_MAX;
+ }
+ quint32 tooBigIndex() const
+ {
+ quint32 retn = 7;
+ retn += INT_MAX;
+ return retn;
+ }
+ qint32 negativeIndex() const
+ {
+ return -5;
+ }
+
+ QList<int> intListProperty() const { return m_intList; }
+ void setIntListProperty(const QList<int> &list) { m_intList = list; emit intListPropertyChanged(); }
+ QList<int> intListProperty2() const { return m_intList2; }
+ void setIntListProperty2(const QList<int> &list) { m_intList2 = list; emit intListProperty2Changed(); }
+ QList<qreal> qrealListProperty() const { return m_qrealList; }
+ void setQrealListProperty(const QList<qreal> &list) { m_qrealList = list; emit qrealListPropertyChanged(); }
+ QList<bool> boolListProperty() const { return m_boolList; }
+ void setBoolListProperty(const QList<bool> &list) { m_boolList = list; emit boolListPropertyChanged(); }
+ QList<QString> stringListProperty() const { return m_stringList; }
+ void setStringListProperty(const QList<QString> &list) { m_stringList = list; emit stringListPropertyChanged(); }
+ QList<QUrl> urlListProperty() const { return m_urlList; }
+ void setUrlListProperty(const QList<QUrl> &list) { m_urlList = list; emit urlListPropertyChanged(); }
+ QStringList qstringListProperty() const { return m_qstringList; }
+ void setQStringListProperty(const QStringList &list) { m_qstringList = list; emit qstringListPropertyChanged(); }
+ QList<QPoint> pointListProperty() const { return m_pointList; }
+ void setPointListProperty(const QList<QPoint> &list) { m_pointList = list; emit pointListPropertyChanged(); }
+ QList<QVariant> variantListProperty() const { return m_variantList; }
+ void setVariantListProperty(const QList<QVariant> &list) { m_variantList = list; emit variantListPropertyChanged(); }
+
+ // now for "copy resource" sequences:
+ Q_INVOKABLE QList<int> generateIntSequence() const { QList<int> retn; retn << 1 << 2 << 3; return retn; }
+ Q_INVOKABLE QList<qreal> generateQrealSequence() const { QList<qreal> retn; retn << 1.1 << 2.2 << 3.3; return retn; }
+ Q_INVOKABLE QList<bool> generateBoolSequence() const { QList<bool> retn; retn << true << false << true; return retn; }
+ Q_INVOKABLE QList<QString> generateStringSequence() const { QList<QString> retn; retn << "one" << "two" << "three"; return retn; }
+ Q_INVOKABLE QList<QUrl> generateUrlSequence() const { QList<QUrl> retn; retn << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com"); return retn; }
+ Q_INVOKABLE QStringList generateQStringSequence() const { QStringList retn; retn << "one" << "two" << "three"; return retn; }
+
+ // "reference resource" underlying qobject deletion test:
+ Q_INVOKABLE MySequenceConversionObject *generateTestObject() const { return new MySequenceConversionObject; }
+ Q_INVOKABLE void deleteTestObject(QObject *object) const { delete object; }
+
+signals:
+ void intListPropertyChanged();
+ void intListProperty2Changed();
+ void qrealListPropertyChanged();
+ void boolListPropertyChanged();
+ void stringListPropertyChanged();
+ void urlListPropertyChanged();
+ void qstringListPropertyChanged();
+ void pointListPropertyChanged();
+ void variantListPropertyChanged();
+
+private:
+ QList<int> m_intList;
+ QList<int> m_intList2;
+ QList<qreal> m_qrealList;
+ QList<bool> m_boolList;
+ QList<QString> m_stringList;
+ QList<QUrl> m_urlList;
+ QStringList m_qstringList;
+
+ QList<QPoint> m_pointList; // not a supported sequence type
+ QList<QVariant> m_variantList; // not a supported sequence type, but QVariantList support is hardcoded.
+};
+
+class MyDeleteObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QObject *nestedObject READ nestedObject NOTIFY nestedObjectChanged);
+ Q_PROPERTY(int deleteNestedObject READ deleteNestedObject NOTIFY deleteNestedObjectChanged);
+
+public:
+ MyDeleteObject() : m_nestedObject(new MyQmlObject) {}
+
+ QObject *nestedObject() const { return m_nestedObject; }
+ int deleteNestedObject() { delete m_nestedObject; m_nestedObject = 0; return 1; }
+
+signals:
+ void nestedObjectChanged();
+ void deleteNestedObjectChanged();
+
+private:
+ MyQmlObject *m_nestedObject;
+};
+
+void registerTypes();
+
+#endif // TESTTYPES_H
+
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
new file mode 100644
index 0000000000..676557a81c
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -0,0 +1,6097 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtTest/QtTest>
+#include <QtQml/qqmlcomponent.h>
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlexpression.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qdebug.h>
+#include <QtQml/private/qqmlguard_p.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qnumeric.h>
+#include <private/qqmlengine_p.h>
+#include <private/qqmlvmemetaobject_p.h>
+#include <private/qv4compiler_p.h>
+#include "testtypes.h"
+#include "testhttpserver.h"
+#include "../../shared/util.h"
+
+/*
+This test covers evaluation of ECMAScript expressions and bindings from within
+QML. This does not include static QML language issues.
+
+Static QML language issues are covered in qmllanguage
+*/
+
+class tst_qqmlecmascript : public QQmlDataTest
+{
+ Q_OBJECT
+public:
+ tst_qqmlecmascript() {}
+
+private slots:
+ void initTestCase();
+ void assignBasicTypes();
+ void idShortcutInvalidates();
+ void boolPropertiesEvaluateAsBool();
+ void methods();
+ void signalAssignment();
+ void bindingLoop();
+ void basicExpressions();
+ void basicExpressions_data();
+ void arrayExpressions();
+ void contextPropertiesTriggerReeval();
+ void objectPropertiesTriggerReeval();
+ void deferredProperties();
+ void deferredPropertiesErrors();
+ void extensionObjects();
+ void overrideExtensionProperties();
+ void attachedProperties();
+ void enums();
+ void valueTypeFunctions();
+ void constantsOverrideBindings();
+ void outerBindingOverridesInnerBinding();
+ void aliasPropertyAndBinding();
+ void aliasPropertyReset();
+ void nonExistentAttachedObject();
+ void scope();
+ void importScope();
+ void signalParameterTypes();
+ void objectsCompareAsEqual();
+ void dynamicCreation_data();
+ void dynamicCreation();
+ void dynamicDestruction();
+ void objectToString();
+ void objectHasOwnProperty();
+ void selfDeletingBinding();
+ void extendedObjectPropertyLookup();
+ void extendedObjectPropertyLookup2();
+ void scriptErrors();
+ void functionErrors();
+ void propertyAssignmentErrors();
+ void signalTriggeredBindings();
+ void listProperties();
+ void exceptionClearsOnReeval();
+ void exceptionSlotProducesWarning();
+ void exceptionBindingProducesWarning();
+ void compileInvalidBinding();
+ void transientErrors();
+ void shutdownErrors();
+ void compositePropertyType();
+ void jsObject();
+ void undefinedResetsProperty();
+ void listToVariant();
+ void listAssignment();
+ void multiEngineObject();
+ void deletedObject();
+ void attachedPropertyScope();
+ void scriptConnect();
+ void scriptDisconnect();
+ void ownership();
+ void cppOwnershipReturnValue();
+ void ownershipCustomReturnValue();
+ void qlistqobjectMethods();
+ void strictlyEquals();
+ void compiled();
+ void numberAssignment();
+ void propertySplicing();
+ void signalWithUnknownTypes();
+ void signalWithJSValueInVariant_data();
+ void signalWithJSValueInVariant();
+ void signalWithJSValueInVariant_twoEngines_data();
+ void signalWithJSValueInVariant_twoEngines();
+ void signalWithQJSValue_data();
+ void signalWithQJSValue();
+ void moduleApi_data();
+ void moduleApi();
+ void importScripts_data();
+ void importScripts();
+ void scarceResources();
+ void scarceResources_data();
+ void scarceResources_other();
+ void propertyChangeSlots();
+ void propertyVar_data();
+ void propertyVar();
+ void propertyVarCpp();
+ void propertyVarOwnership();
+ void propertyVarImplicitOwnership();
+ void propertyVarReparent();
+ void propertyVarReparentNullContext();
+ void propertyVarCircular();
+ void propertyVarCircular2();
+ void propertyVarInheritance();
+ void propertyVarInheritance2();
+ void elementAssign();
+ void objectPassThroughSignals();
+ void objectConversion();
+ void booleanConversion();
+ void handleReferenceManagement();
+ void stringArg();
+ void readonlyDeclaration();
+ void sequenceConversionRead();
+ void sequenceConversionWrite();
+ void sequenceConversionArray();
+ void sequenceConversionIndexes();
+ void sequenceConversionThreads();
+ void sequenceConversionBindings();
+ void sequenceConversionCopy();
+ void assignSequenceTypes();
+ void qtbug_22464();
+ void qtbug_21580();
+
+ void bug1();
+ void bug2();
+ void dynamicCreationCrash();
+ void dynamicCreationOwnership();
+ void regExpBug();
+ void nullObjectBinding();
+ void deletedEngine();
+ void libraryScriptAssert();
+ void variantsAssignedUndefined();
+ void qtbug_9792();
+ void qtcreatorbug_1289();
+ void noSpuriousWarningsAtShutdown();
+ void canAssignNullToQObject();
+ void functionAssignment_fromBinding();
+ void functionAssignment_fromJS();
+ void functionAssignment_fromJS_data();
+ void functionAssignmentfromJS_invalid();
+ void eval();
+ void function();
+ void functionException();
+ void qtbug_10696();
+ void qtbug_11606();
+ void qtbug_11600();
+ void qtbug_21864();
+ void qobjectConnectionListExceptionHandling();
+ void nonscriptable();
+ void deleteLater();
+ void in();
+ void typeOf();
+ void sharedAttachedObject();
+ void objectName();
+ void writeRemovesBinding();
+ void aliasBindingsAssignCorrectly();
+ void aliasBindingsOverrideTarget();
+ void aliasWritesOverrideBindings();
+ void aliasToCompositeElement();
+ void realToInt();
+ void urlProperty();
+ void urlPropertyWithEncoding();
+ void urlListPropertyWithEncoding();
+ void dynamicString();
+ void include();
+ void signalHandlers();
+ void doubleEvaluate();
+ void forInLoop();
+ void nonNotifyable();
+ void deleteWhileBindingRunning();
+ void callQtInvokables();
+ void invokableObjectArg();
+ void invokableObjectRet();
+ void qtbug_20344();
+ void qtbug_22679();
+ void qtbug_22843_data();
+ void qtbug_22843();
+ void rewriteMultiLineStrings();
+ void revisionErrors();
+ void revision();
+ void invokableWithQObjectDerived();
+
+ void automaticSemicolon();
+ void unaryExpression();
+ void switchStatement();
+ void withStatement();
+ void tryStatement();
+
+private:
+ static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
+ QQmlEngine engine;
+};
+
+void tst_qqmlecmascript::initTestCase()
+{
+ QQmlDataTest::initTestCase();
+ registerTypes();
+}
+
+void tst_qqmlecmascript::assignBasicTypes()
+{
+ {
+ QQmlComponent component(&engine, testFileUrl("assignBasicTypes.qml"));
+ MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
+ QVERIFY(object != 0);
+ QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
+ QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
+ QCOMPARE(object->stringProperty(), QString("Hello World!"));
+ QCOMPARE(object->uintProperty(), uint(10));
+ QCOMPARE(object->intProperty(), -19);
+ QCOMPARE((float)object->realProperty(), float(23.2));
+ QCOMPARE((float)object->doubleProperty(), float(-19.75));
+ QCOMPARE((float)object->floatProperty(), float(8.5));
+ QCOMPARE(object->colorProperty(), QColor("red"));
+ QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
+ QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
+ QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
+ QCOMPARE(object->pointProperty(), QPoint(99,13));
+ QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
+ QCOMPARE(object->sizeProperty(), QSize(99, 13));
+ QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
+ QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
+ QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
+ QCOMPARE(object->boolProperty(), true);
+ QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
+ QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
+ QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
+ delete object;
+ }
+ {
+ QQmlComponent component(&engine, testFileUrl("assignBasicTypes.2.qml"));
+ MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
+ QVERIFY(object != 0);
+ QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
+ QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
+ QCOMPARE(object->stringProperty(), QString("Hello World!"));
+ QCOMPARE(object->uintProperty(), uint(10));
+ QCOMPARE(object->intProperty(), -19);
+ QCOMPARE((float)object->realProperty(), float(23.2));
+ QCOMPARE((float)object->doubleProperty(), float(-19.75));
+ QCOMPARE((float)object->floatProperty(), float(8.5));
+ QCOMPARE(object->colorProperty(), QColor("red"));
+ QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
+ QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
+ QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
+ QCOMPARE(object->pointProperty(), QPoint(99,13));
+ QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
+ QCOMPARE(object->sizeProperty(), QSize(99, 13));
+ QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
+ QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
+ QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
+ QCOMPARE(object->boolProperty(), true);
+ QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
+ QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
+ QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
+ delete object;
+ }
+}
+
+void tst_qqmlecmascript::idShortcutInvalidates()
+{
+ {
+ QQmlComponent component(&engine, testFileUrl("idShortcutInvalidates.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+ QVERIFY(object->objectProperty() != 0);
+ delete object->objectProperty();
+ QVERIFY(object->objectProperty() == 0);
+ delete object;
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("idShortcutInvalidates.1.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+ QVERIFY(object->objectProperty() != 0);
+ delete object->objectProperty();
+ QVERIFY(object->objectProperty() == 0);
+ delete object;
+ }
+}
+
+void tst_qqmlecmascript::boolPropertiesEvaluateAsBool()
+{
+ {
+ QQmlComponent component(&engine, testFileUrl("boolPropertiesEvaluateAsBool.1.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+ QCOMPARE(object->stringProperty(), QLatin1String("pass"));
+ delete object;
+ }
+ {
+ QQmlComponent component(&engine, testFileUrl("boolPropertiesEvaluateAsBool.2.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+ QCOMPARE(object->stringProperty(), QLatin1String("pass"));
+ delete object;
+ }
+}
+
+void tst_qqmlecmascript::signalAssignment()
+{
+ {
+ QQmlComponent component(&engine, testFileUrl("signalAssignment.1.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+ QCOMPARE(object->string(), QString());
+ emit object->basicSignal();
+ QCOMPARE(object->string(), QString("pass"));
+ delete object;
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("signalAssignment.2.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+ 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"));
+ delete object;
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("signalAssignment.3.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+ QCOMPARE(object->string(), QString());
+ emit object->unnamedArgumentSignal(19, 10.25, "Hello world!");
+ QEXPECT_FAIL("", "QTBUG-24481", Continue);
+ QCOMPARE(object->string(), QString("pass 19 Hello world!"));
+ delete object;
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("signalAssignment.4.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+ QCOMPARE(object->string(), QString());
+ emit object->signalWithGlobalName(19);
+ QCOMPARE(object->string(), QString("pass 5"));
+ delete object;
+ }
+}
+
+void tst_qqmlecmascript::methods()
+{
+ {
+ QQmlComponent component(&engine, testFileUrl("methods.1.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+ QCOMPARE(object->methodCalled(), false);
+ QCOMPARE(object->methodIntCalled(), false);
+ emit object->basicSignal();
+ QCOMPARE(object->methodCalled(), true);
+ QCOMPARE(object->methodIntCalled(), false);
+ delete object;
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("methods.2.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+ QCOMPARE(object->methodCalled(), false);
+ QCOMPARE(object->methodIntCalled(), false);
+ emit object->basicSignal();
+ QCOMPARE(object->methodCalled(), false);
+ QCOMPARE(object->methodIntCalled(), true);
+ delete object;
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("methods.3.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ QCOMPARE(object->property("test").toInt(), 19);
+ delete object;
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("methods.4.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ QCOMPARE(object->property("test").toInt(), 19);
+ QCOMPARE(object->property("test2").toInt(), 17);
+ QCOMPARE(object->property("test3").toInt(), 16);
+ delete object;
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("methods.5.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ QCOMPARE(object->property("test").toInt(), 9);
+ delete object;
+ }
+}
+
+void tst_qqmlecmascript::bindingLoop()
+{
+ QQmlComponent component(&engine, testFileUrl("bindingLoop.qml"));
+ QString warning = component.url().toString() + ":5:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
+ QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ delete object;
+}
+
+void tst_qqmlecmascript::basicExpressions_data()
+{
+ QTest::addColumn<QString>("expression");
+ QTest::addColumn<QVariant>("result");
+ QTest::addColumn<bool>("nest");
+
+ QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
+ QTest::newRow("Context property") << "a" << QVariant(1944) << false;
+ QTest::newRow("Context property") << "a" << QVariant(1944) << true;
+ QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
+ QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
+ QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
+ QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
+ QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
+ QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
+ QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
+ QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
+ QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
+ QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
+ QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
+ QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
+ QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
+ QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
+ QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
+ QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
+}
+
+void tst_qqmlecmascript::basicExpressions()
+{
+ QFETCH(QString, expression);
+ QFETCH(QVariant, result);
+ QFETCH(bool, nest);
+
+ MyQmlObject object1;
+ MyQmlObject object2;
+ MyQmlObject object3;
+ MyDefaultObject1 default1;
+ MyDefaultObject3 default3;
+ object1.setStringProperty("Object1");
+ object2.setStringProperty("Object2");
+ object3.setStringProperty("Object3");
+
+ QQmlContext context(engine.rootContext());
+ QQmlContext nestedContext(&context);
+
+ context.setContextObject(&default1);
+ context.setContextProperty("a", QVariant(1944));
+ context.setContextProperty("b", QVariant("Milk"));
+ context.setContextProperty("object", &object1);
+ context.setContextProperty("objectOverride", &object2);
+ nestedContext.setContextObject(&default3);
+ nestedContext.setContextProperty("b", QVariant("Cow"));
+ nestedContext.setContextProperty("objectOverride", &object3);
+ nestedContext.setContextProperty("millipedeLegs", QVariant(100));
+
+ MyExpression expr(nest?&nestedContext:&context, expression);
+ QCOMPARE(expr.evaluate(), result);
+}
+
+void tst_qqmlecmascript::arrayExpressions()
+{
+ QObject obj1;
+ QObject obj2;
+ QObject obj3;
+
+ QQmlContext context(engine.rootContext());
+ context.setContextProperty("a", &obj1);
+ context.setContextProperty("b", &obj2);
+ context.setContextProperty("c", &obj3);
+
+ MyExpression expr(&context, "[a, b, c, 10]");
+ QVariant result = expr.evaluate();
+ QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
+ QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
+ QCOMPARE(list.count(), 4);
+ QCOMPARE(list.at(0), &obj1);
+ QCOMPARE(list.at(1), &obj2);
+ QCOMPARE(list.at(2), &obj3);
+ QCOMPARE(list.at(3), (QObject *)0);
+}
+
+// Tests that modifying a context property will reevaluate expressions
+void tst_qqmlecmascript::contextPropertiesTriggerReeval()
+{
+ QQmlContext context(engine.rootContext());
+ MyQmlObject object1;
+ MyQmlObject object2;
+ MyQmlObject *object3 = new MyQmlObject;
+
+ object1.setStringProperty("Hello");
+ object2.setStringProperty("World");
+
+ context.setContextProperty("testProp", QVariant(1));
+ context.setContextProperty("testObj", &object1);
+ context.setContextProperty("testObj2", object3);
+
+ {
+ MyExpression expr(&context, "testProp + 1");
+ QCOMPARE(expr.changed, false);
+ QCOMPARE(expr.evaluate(), QVariant(2));
+
+ context.setContextProperty("testProp", QVariant(2));
+ QCOMPARE(expr.changed, true);
+ QCOMPARE(expr.evaluate(), QVariant(3));
+ }
+
+ {
+ MyExpression expr(&context, "testProp + testProp + testProp");
+ QCOMPARE(expr.changed, false);
+ QCOMPARE(expr.evaluate(), QVariant(6));
+
+ context.setContextProperty("testProp", QVariant(4));
+ QCOMPARE(expr.changed, true);
+ QCOMPARE(expr.evaluate(), QVariant(12));
+ }
+
+ {
+ MyExpression expr(&context, "testObj.stringProperty");
+ QCOMPARE(expr.changed, false);
+ QCOMPARE(expr.evaluate(), QVariant("Hello"));
+
+ context.setContextProperty("testObj", &object2);
+ QCOMPARE(expr.changed, true);
+ QCOMPARE(expr.evaluate(), QVariant("World"));
+ }
+
+ {
+ MyExpression expr(&context, "testObj.stringProperty /**/");
+ QCOMPARE(expr.changed, false);
+ QCOMPARE(expr.evaluate(), QVariant("World"));
+
+ context.setContextProperty("testObj", &object1);
+ QCOMPARE(expr.changed, true);
+ QCOMPARE(expr.evaluate(), QVariant("Hello"));
+ }
+
+ {
+ MyExpression expr(&context, "testObj2");
+ QCOMPARE(expr.changed, false);
+ QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
+ }
+
+ delete object3;
+}
+
+void tst_qqmlecmascript::objectPropertiesTriggerReeval()
+{
+ QQmlContext context(engine.rootContext());
+ MyQmlObject object1;
+ MyQmlObject object2;
+ MyQmlObject object3;
+ context.setContextProperty("testObj", &object1);
+
+ object1.setStringProperty(QLatin1String("Hello"));
+ object2.setStringProperty(QLatin1String("Dog"));
+ object3.setStringProperty(QLatin1String("Cat"));
+
+ {
+ MyExpression expr(&context, "testObj.stringProperty");
+ QCOMPARE(expr.changed, false);
+ QCOMPARE(expr.evaluate(), QVariant("Hello"));
+
+ object1.setStringProperty(QLatin1String("World"));
+ QCOMPARE(expr.changed, true);
+ QCOMPARE(expr.evaluate(), QVariant("World"));
+ }
+
+ {
+ MyExpression expr(&context, "testObj.objectProperty.stringProperty");
+ QCOMPARE(expr.changed, false);
+ QCOMPARE(expr.evaluate(), QVariant());
+
+ object1.setObjectProperty(&object2);
+ QCOMPARE(expr.changed, true);
+ expr.changed = false;
+ QCOMPARE(expr.evaluate(), QVariant("Dog"));
+
+ object1.setObjectProperty(&object3);
+ QCOMPARE(expr.changed, true);
+ expr.changed = false;
+ QCOMPARE(expr.evaluate(), QVariant("Cat"));
+
+ object1.setObjectProperty(0);
+ QCOMPARE(expr.changed, true);
+ expr.changed = false;
+ QCOMPARE(expr.evaluate(), QVariant());
+
+ object1.setObjectProperty(&object3);
+ QCOMPARE(expr.changed, true);
+ expr.changed = false;
+ QCOMPARE(expr.evaluate(), QVariant("Cat"));
+
+ object3.setStringProperty("Donkey");
+ QCOMPARE(expr.changed, true);
+ expr.changed = false;
+ QCOMPARE(expr.evaluate(), QVariant("Donkey"));
+ }
+}
+
+void tst_qqmlecmascript::deferredProperties()
+{
+ QQmlComponent component(&engine, testFileUrl("deferredProperties.qml"));
+ MyDeferredObject *object =
+ qobject_cast<MyDeferredObject *>(component.create());
+ QVERIFY(object != 0);
+ QCOMPARE(object->value(), 0);
+ QVERIFY(object->objectProperty() == 0);
+ QVERIFY(object->objectProperty2() != 0);
+ qmlExecuteDeferred(object);
+ QCOMPARE(object->value(), 10);
+ QVERIFY(object->objectProperty() != 0);
+ MyQmlObject *qmlObject =
+ qobject_cast<MyQmlObject *>(object->objectProperty());
+ QVERIFY(qmlObject != 0);
+ QCOMPARE(qmlObject->value(), 10);
+ object->setValue(19);
+ QCOMPARE(qmlObject->value(), 19);
+
+ delete object;
+}
+
+// Check errors on deferred properties are correctly emitted
+void tst_qqmlecmascript::deferredPropertiesErrors()
+{
+ QQmlComponent component(&engine, testFileUrl("deferredPropertiesErrors.qml"));
+ MyDeferredObject *object =
+ qobject_cast<MyDeferredObject *>(component.create());
+ QVERIFY(object != 0);
+ QCOMPARE(object->value(), 0);
+ QVERIFY(object->objectProperty() == 0);
+ QVERIFY(object->objectProperty2() == 0);
+
+ QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject*";
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
+
+ qmlExecuteDeferred(object);
+
+ delete object;
+}
+
+void tst_qqmlecmascript::extensionObjects()
+{
+ QQmlComponent component(&engine, testFileUrl("extensionObjects.qml"));
+ MyExtendedObject *object =
+ qobject_cast<MyExtendedObject *>(component.create());
+ QVERIFY(object != 0);
+ QCOMPARE(object->baseProperty(), 13);
+ QCOMPARE(object->coreProperty(), 9);
+ object->setProperty("extendedProperty", QVariant(11));
+ object->setProperty("baseExtendedProperty", QVariant(92));
+ QCOMPARE(object->coreProperty(), 11);
+ QCOMPARE(object->baseProperty(), 92);
+
+ MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
+ QVERIFY(nested);
+ QCOMPARE(nested->baseProperty(), 13);
+ QCOMPARE(nested->coreProperty(), 9);
+ nested->setProperty("extendedProperty", QVariant(11));
+ nested->setProperty("baseExtendedProperty", QVariant(92));
+ QCOMPARE(nested->coreProperty(), 11);
+ QCOMPARE(nested->baseProperty(), 92);
+
+ delete object;
+}
+
+void tst_qqmlecmascript::overrideExtensionProperties()
+{
+ QQmlComponent component(&engine, testFileUrl("extensionObjectsPropertyOverride.qml"));
+ OverrideDefaultPropertyObject *object =
+ qobject_cast<OverrideDefaultPropertyObject *>(component.create());
+ QVERIFY(object != 0);
+ QVERIFY(object->secondProperty() != 0);
+ QVERIFY(object->firstProperty() == 0);
+
+ delete object;
+}
+
+void tst_qqmlecmascript::attachedProperties()
+{
+ {
+ QQmlComponent component(&engine, testFileUrl("attachedProperty.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ QCOMPARE(object->property("a").toInt(), 19);
+ QCOMPARE(object->property("b").toInt(), 19);
+ QCOMPARE(object->property("c").toInt(), 19);
+ QCOMPARE(object->property("d").toInt(), 19);
+ delete object;
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("attachedProperty.2.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ QCOMPARE(object->property("a").toInt(), 26);
+ QCOMPARE(object->property("b").toInt(), 26);
+ QCOMPARE(object->property("c").toInt(), 26);
+ QCOMPARE(object->property("d").toInt(), 26);
+
+ delete object;
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("writeAttachedProperty.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QMetaObject::invokeMethod(object, "writeValue2");
+
+ MyQmlAttachedObject *attached =
+ qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
+ QVERIFY(attached != 0);
+
+ QCOMPARE(attached->value2(), 9);
+ delete object;
+ }
+}
+
+void tst_qqmlecmascript::enums()
+{
+ // Existent enums
+ {
+ QQmlComponent component(&engine, testFileUrl("enums.1.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("a").toInt(), 0);
+ QCOMPARE(object->property("b").toInt(), 1);
+ QCOMPARE(object->property("c").toInt(), 2);
+ QCOMPARE(object->property("d").toInt(), 3);
+ QCOMPARE(object->property("e").toInt(), 0);
+ QCOMPARE(object->property("f").toInt(), 1);
+ QCOMPARE(object->property("g").toInt(), 2);
+ QCOMPARE(object->property("h").toInt(), 3);
+ QCOMPARE(object->property("i").toInt(), 19);
+ QCOMPARE(object->property("j").toInt(), 19);
+
+ delete object;
+ }
+ // Non-existent enums
+ {
+ QQmlComponent component(&engine, testFileUrl("enums.2.qml"));
+
+ QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int";
+ QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int";
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ QCOMPARE(object->property("a").toInt(), 0);
+ QCOMPARE(object->property("b").toInt(), 0);
+
+ delete object;
+ }
+}
+
+void tst_qqmlecmascript::valueTypeFunctions()
+{
+ QQmlComponent component(&engine, testFileUrl("valueTypeFunctions.qml"));
+ MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
+ QVERIFY(obj != 0);
+ QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
+ QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
+
+ delete obj;
+}
+
+/*
+Tests that writing a constant to a property with a binding on it disables the
+binding.
+*/
+void tst_qqmlecmascript::constantsOverrideBindings()
+{
+ // From ECMAScript
+ {
+ QQmlComponent component(&engine, testFileUrl("constantsOverrideBindings.1.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("c2").toInt(), 0);
+ object->setProperty("c1", QVariant(9));
+ QCOMPARE(object->property("c2").toInt(), 9);
+
+ emit object->basicSignal();
+
+ QCOMPARE(object->property("c2").toInt(), 13);
+ object->setProperty("c1", QVariant(8));
+ QCOMPARE(object->property("c2").toInt(), 13);
+
+ delete object;
+ }
+
+ // During construction
+ {
+ QQmlComponent component(&engine, testFileUrl("constantsOverrideBindings.2.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("c1").toInt(), 0);
+ QCOMPARE(object->property("c2").toInt(), 10);
+ object->setProperty("c1", QVariant(9));
+ QCOMPARE(object->property("c1").toInt(), 9);
+ QCOMPARE(object->property("c2").toInt(), 10);
+
+ delete object;
+ }
+
+#if 0
+ // From C++
+ {
+ QQmlComponent component(&engine, testFileUrl("constantsOverrideBindings.3.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("c2").toInt(), 0);
+ object->setProperty("c1", QVariant(9));
+ QCOMPARE(object->property("c2").toInt(), 9);
+
+ object->setProperty("c2", QVariant(13));
+ QCOMPARE(object->property("c2").toInt(), 13);
+ object->setProperty("c1", QVariant(7));
+ QCOMPARE(object->property("c1").toInt(), 7);
+ QCOMPARE(object->property("c2").toInt(), 13);
+
+ delete object;
+ }
+#endif
+
+ // Using an alias
+ {
+ QQmlComponent component(&engine, testFileUrl("constantsOverrideBindings.4.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("c1").toInt(), 0);
+ QCOMPARE(object->property("c3").toInt(), 10);
+ object->setProperty("c1", QVariant(9));
+ QCOMPARE(object->property("c1").toInt(), 9);
+ QCOMPARE(object->property("c3").toInt(), 10);
+
+ delete object;
+ }
+}
+
+/*
+Tests that assigning a binding to a property that already has a binding causes
+the original binding to be disabled.
+*/
+void tst_qqmlecmascript::outerBindingOverridesInnerBinding()
+{
+ QQmlComponent component(&engine,
+ testFileUrl("outerBindingOverridesInnerBinding.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("c1").toInt(), 0);
+ QCOMPARE(object->property("c2").toInt(), 0);
+ QCOMPARE(object->property("c3").toInt(), 0);
+
+ object->setProperty("c1", QVariant(9));
+ QCOMPARE(object->property("c1").toInt(), 9);
+ QCOMPARE(object->property("c2").toInt(), 0);
+ QCOMPARE(object->property("c3").toInt(), 0);
+
+ object->setProperty("c3", QVariant(8));
+ QCOMPARE(object->property("c1").toInt(), 9);
+ QCOMPARE(object->property("c2").toInt(), 8);
+ QCOMPARE(object->property("c3").toInt(), 8);
+
+ delete object;
+}
+
+/*
+Access a non-existent attached object.
+
+Tests for a regression where this used to crash.
+*/
+void tst_qqmlecmascript::nonExistentAttachedObject()
+{
+ QQmlComponent component(&engine, testFileUrl("nonExistentAttachedObject.qml"));
+
+ QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString";
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ delete object;
+}
+
+void tst_qqmlecmascript::scope()
+{
+ {
+ QQmlComponent component(&engine, testFileUrl("scope.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test1").toInt(), 1);
+ QCOMPARE(object->property("test2").toInt(), 2);
+ QCOMPARE(object->property("test3").toString(), QString("1Test"));
+ QCOMPARE(object->property("test4").toString(), QString("2Test"));
+ QCOMPARE(object->property("test5").toInt(), 1);
+ QCOMPARE(object->property("test6").toInt(), 1);
+ QCOMPARE(object->property("test7").toInt(), 2);
+ QCOMPARE(object->property("test8").toInt(), 2);
+ QCOMPARE(object->property("test9").toInt(), 1);
+ QCOMPARE(object->property("test10").toInt(), 3);
+
+ delete object;
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("scope.2.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test1").toInt(), 19);
+ QCOMPARE(object->property("test2").toInt(), 19);
+ QCOMPARE(object->property("test3").toInt(), 14);
+ QCOMPARE(object->property("test4").toInt(), 14);
+ QCOMPARE(object->property("test5").toInt(), 24);
+ QCOMPARE(object->property("test6").toInt(), 24);
+
+ delete object;
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("scope.3.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test1").toBool(), true);
+ QCOMPARE(object->property("test2").toBool(), true);
+ QCOMPARE(object->property("test3").toBool(), true);
+
+ delete object;
+ }
+
+ // Signal argument scope
+ {
+ QQmlComponent component(&engine, testFileUrl("scope.4.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test").toInt(), 0);
+ QCOMPARE(object->property("test2").toString(), QString());
+
+ emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
+
+ QCOMPARE(object->property("test").toInt(), 13);
+ QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
+
+ delete object;
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("scope.5.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test1").toBool(), true);
+ QCOMPARE(object->property("test2").toBool(), true);
+
+ delete object;
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("scope.6.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test").toBool(), true);
+
+ delete object;
+ }
+}
+
+// In 4.7, non-library javascript files that had no imports shared the imports of their
+// importing context
+void tst_qqmlecmascript::importScope()
+{
+ QQmlComponent component(&engine, testFileUrl("importScope.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ QCOMPARE(o->property("test").toInt(), 240);
+
+ delete o;
+}
+
+/*
+Tests that "any" type passes through a synthesized signal parameter. This
+is essentially a test of QQmlMetaType::copy()
+*/
+void tst_qqmlecmascript::signalParameterTypes()
+{
+ QQmlComponent component(&engine, testFileUrl("signalParameterTypes.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ emit object->basicSignal();
+
+ QCOMPARE(object->property("intProperty").toInt(), 10);
+ QCOMPARE(object->property("realProperty").toReal(), 19.2);
+ QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
+ QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
+ QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
+ QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
+
+ delete object;
+}
+
+/*
+Test that two JS objects for the same QObject compare as equal.
+*/
+void tst_qqmlecmascript::objectsCompareAsEqual()
+{
+ QQmlComponent component(&engine, testFileUrl("objectsCompareAsEqual.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test1").toBool(), true);
+ QCOMPARE(object->property("test2").toBool(), true);
+ QCOMPARE(object->property("test3").toBool(), true);
+ QCOMPARE(object->property("test4").toBool(), true);
+ QCOMPARE(object->property("test5").toBool(), true);
+
+ delete object;
+}
+
+/*
+Confirm bindings and alias properties can coexist.
+
+Tests for a regression where the binding would not reevaluate.
+*/
+void tst_qqmlecmascript::aliasPropertyAndBinding()
+{
+ QQmlComponent component(&engine, testFileUrl("aliasPropertyAndBinding.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("c2").toInt(), 3);
+ QCOMPARE(object->property("c3").toInt(), 3);
+
+ object->setProperty("c2", QVariant(19));
+
+ QCOMPARE(object->property("c2").toInt(), 19);
+ QCOMPARE(object->property("c3").toInt(), 19);
+
+ delete object;
+}
+
+/*
+Ensure that we can write undefined value to an alias property,
+and that the aliased property is reset correctly if possible.
+*/
+void tst_qqmlecmascript::aliasPropertyReset()
+{
+ QObject *object = 0;
+
+ // 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->property("sourceComponentAlias").value<QQmlComponent*>() != 0);
+ QCOMPARE(object->property("aliasIsUndefined"), QVariant(false));
+ QMetaObject::invokeMethod(object, "resetAliased");
+ QVERIFY(object->property("sourceComponentAlias").value<QQmlComponent*>() == 0);
+ QCOMPARE(object->property("aliasIsUndefined"), QVariant(true));
+ delete object;
+
+ // 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->property("sourceComponentAlias").value<QQmlComponent*>() != 0);
+ QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(false));
+ QMetaObject::invokeMethod(object, "resetAlias");
+ QVERIFY(object->property("sourceComponentAlias").value<QQmlComponent*>() == 0);
+ QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(true));
+ delete object;
+
+ // 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->property("sourceComponentAlias").value<QQmlComponent*>() != 0);
+ QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(false));
+ QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
+ QMetaObject::invokeMethod(object, "resetAlias");
+ QVERIFY(object->property("sourceComponentAlias").value<QQmlComponent*>() == 0);
+ QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(true));
+ QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
+ delete object;
+
+ // test that a manual write (of undefined) to a resettable alias property
+ // 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->property("sourceComponentAlias").value<QQmlComponent*>() != 0);
+ QObject *loader = object->findChild<QObject*>("loader");
+ QVERIFY(loader != 0);
+ delete loader;
+ QVERIFY(object->property("sourceComponentAlias").value<QQmlComponent*>() == 0); // deletion should have caused value unset.
+ QMetaObject::invokeMethod(object, "resetAlias"); // shouldn't crash.
+ QVERIFY(object->property("sourceComponentAlias").value<QQmlComponent*>() == 0);
+ QMetaObject::invokeMethod(object, "setAlias"); // shouldn't crash, and shouldn't change value (since it's no longer referencing anything).
+ QVERIFY(object->property("sourceComponentAlias").value<QQmlComponent*>() == 0);
+ delete object;
+
+ // 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->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");
+ QQmlComponent e1(&engine, url);
+ object = e1.create();
+ QVERIFY(object != 0);
+ QCOMPARE(object->property("intAlias").value<int>(), 12);
+ QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
+ QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
+ QMetaObject::invokeMethod(object, "resetAlias");
+ QCOMPARE(object->property("intAlias").value<int>(), 12);
+ QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
+ delete object;
+}
+
+void tst_qqmlecmascript::dynamicCreation_data()
+{
+ QTest::addColumn<QString>("method");
+ QTest::addColumn<QString>("createdName");
+
+ QTest::newRow("One") << "createOne" << "objectOne";
+ QTest::newRow("Two") << "createTwo" << "objectTwo";
+ QTest::newRow("Three") << "createThree" << "objectThree";
+}
+
+/*
+Test using createQmlObject to dynamically generate an item
+Also using createComponent is tested.
+*/
+void tst_qqmlecmascript::dynamicCreation()
+{
+ QFETCH(QString, method);
+ QFETCH(QString, createdName);
+
+ QQmlComponent component(&engine, testFileUrl("dynamicCreation.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
+ QVERIFY(object != 0);
+
+ QMetaObject::invokeMethod(object, method.toUtf8());
+ QObject *created = object->objectProperty();
+ QVERIFY(created);
+ QCOMPARE(created->objectName(), createdName);
+
+ delete object;
+}
+
+/*
+ Tests the destroy function
+*/
+void tst_qqmlecmascript::dynamicDestruction()
+{
+ {
+ QQmlComponent component(&engine, testFileUrl("dynamicDeletion.qml"));
+ QQmlGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
+ QVERIFY(object != 0);
+ QQmlGuard<QObject> createdQmlObject = 0;
+
+ QMetaObject::invokeMethod(object, "create");
+ createdQmlObject = object->objectProperty();
+ QVERIFY(createdQmlObject);
+ QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
+
+ QMetaObject::invokeMethod(object, "killOther");
+ QVERIFY(createdQmlObject);
+
+ QCoreApplication::sendPostedEvents(0, 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::processEvents();
+ }
+ }
+ QVERIFY(!createdQmlObject);
+
+ QQmlEngine::setObjectOwnership(object, QQmlEngine::JavaScriptOwnership);
+ QMetaObject::invokeMethod(object, "killMe");
+ QVERIFY(object);
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
+ QVERIFY(!object);
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("dynamicDeletion.2.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
+
+ QMetaObject::invokeMethod(o, "create");
+
+ QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
+
+ QMetaObject::invokeMethod(o, "destroy");
+
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
+
+ QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
+
+ delete o;
+ }
+}
+
+/*
+ tests that id.toString() works
+*/
+void tst_qqmlecmascript::objectToString()
+{
+ QQmlComponent component(&engine, testFileUrl("qmlToString.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
+ QVERIFY(object != 0);
+ QMetaObject::invokeMethod(object, "testToString");
+ QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
+ QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
+
+ delete object;
+}
+
+/*
+ tests that id.hasOwnProperty() works
+*/
+void tst_qqmlecmascript::objectHasOwnProperty()
+{
+ QUrl url = testFileUrl("qmlHasOwnProperty.qml");
+ QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
+ QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
+ QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
+
+ QQmlComponent component(&engine, url);
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ // test QObjects in QML
+ QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
+ QVERIFY(object->property("result").value<bool>() == true);
+ QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
+ QVERIFY(object->property("result").value<bool>() == false);
+
+ // now test other types in QML
+ QObject *child = object->findChild<QObject*>("typeObj");
+ QVERIFY(child != 0);
+ QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
+ QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
+ QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
+ QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
+ QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
+ QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
+ QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
+ QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
+ QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
+ QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
+ QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
+ QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
+
+ QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
+ QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
+ QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
+ QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
+ QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
+ QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
+ QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
+ QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
+ QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
+
+ delete object;
+}
+
+/*
+Tests bindings that indirectly cause their own deletion work.
+
+This test is best run under valgrind to ensure no invalid memory access occur.
+*/
+void tst_qqmlecmascript::selfDeletingBinding()
+{
+ {
+ QQmlComponent component(&engine, testFileUrl("selfDeletingBinding.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ object->setProperty("triggerDelete", true);
+ delete object;
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("selfDeletingBinding.2.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ object->setProperty("triggerDelete", true);
+ delete object;
+ }
+}
+
+/*
+Test that extended object properties can be accessed.
+
+This test a regression where this used to crash. The issue was specificially
+for extended objects that did not include a synthesized meta object (so non-root
+and no synthesiszed properties).
+*/
+void tst_qqmlecmascript::extendedObjectPropertyLookup()
+{
+ QQmlComponent component(&engine, testFileUrl("extendedObjectPropertyLookup.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ delete object;
+}
+
+/*
+Test that extended object properties can be accessed correctly.
+*/
+void tst_qqmlecmascript::extendedObjectPropertyLookup2()
+{
+ QQmlComponent component(&engine, testFileUrl("extendedObjectPropertyLookup2.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QVariant returnValue;
+ QVERIFY(QMetaObject::invokeMethod(object, "getValue", Q_RETURN_ARG(QVariant, returnValue)));
+ QCOMPARE(returnValue.toInt(), 42);
+
+ delete object;
+}
+/*
+Test file/lineNumbers for binding/Script errors.
+*/
+void tst_qqmlecmascript::scriptErrors()
+{
+ QQmlComponent component(&engine, testFileUrl("scriptErrors.qml"));
+ QString url = component.url().toString();
+
+ QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
+ QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
+ QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
+ QString warning4 = url + ":13: ReferenceError: Can't find variable: a";
+ QString warning5 = url + ":11: ReferenceError: Can't find variable: a";
+ QString warning6 = url + ":10: Unable to assign [undefined] to int";
+ QString warning7 = url + ":15: Error: Cannot assign to read-only property \"trueProperty\"";
+ QString warning8 = url + ":16: Error: Cannot assign to non-existent property \"fakeProperty\"";
+
+ QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
+ QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
+ QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
+ QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
+ QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
+ emit object->basicSignal();
+
+ QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
+ emit object->anotherBasicSignal();
+
+ QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
+ emit object->thirdBasicSignal();
+
+ delete object;
+}
+
+/*
+Test file/lineNumbers for inline functions.
+*/
+void tst_qqmlecmascript::functionErrors()
+{
+ QQmlComponent component(&engine, testFileUrl("functionErrors.qml"));
+ QString url = component.url().toString();
+
+ QString warning = url + ":5: Error: Invalid write to global property \"a\"";
+
+ QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ 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);
+
+ QString srpname = object->property("srp_name").toString();
+
+ warning = url + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srpname
+ + QLatin1String(" is not a function");
+ QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
+ QMetaObject::invokeMethod(object, "retrieveScarceResource");
+ delete object;
+}
+
+/*
+Test various errors that can occur when assigning a property from script
+*/
+void tst_qqmlecmascript::propertyAssignmentErrors()
+{
+ QQmlComponent component(&engine, testFileUrl("propertyAssignmentErrors.qml"));
+
+ QString url = component.url().toString();
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test1").toBool(), true);
+ QCOMPARE(object->property("test2").toBool(), true);
+
+ delete object;
+}
+
+/*
+Test bindings still work when the reeval is triggered from within
+a signal script.
+*/
+void tst_qqmlecmascript::signalTriggeredBindings()
+{
+ QQmlComponent component(&engine, testFileUrl("signalTriggeredBindings.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("base").toReal(), 50.);
+ QCOMPARE(object->property("test1").toReal(), 50.);
+ QCOMPARE(object->property("test2").toReal(), 50.);
+
+ object->basicSignal();
+
+ QCOMPARE(object->property("base").toReal(), 200.);
+ QCOMPARE(object->property("test1").toReal(), 200.);
+ QCOMPARE(object->property("test2").toReal(), 200.);
+
+ object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
+
+ QCOMPARE(object->property("base").toReal(), 400.);
+ QCOMPARE(object->property("test1").toReal(), 400.);
+ QCOMPARE(object->property("test2").toReal(), 400.);
+
+ delete object;
+}
+
+/*
+Test that list properties can be iterated from ECMAScript
+*/
+void tst_qqmlecmascript::listProperties()
+{
+ QQmlComponent component(&engine, testFileUrl("listProperties.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test1").toInt(), 21);
+ QCOMPARE(object->property("test2").toInt(), 2);
+ QCOMPARE(object->property("test3").toBool(), true);
+ QCOMPARE(object->property("test4").toBool(), true);
+
+ delete object;
+}
+
+void tst_qqmlecmascript::exceptionClearsOnReeval()
+{
+ QQmlComponent component(&engine, testFileUrl("exceptionClearsOnReeval.qml"));
+ QString url = component.url().toString();
+
+ QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
+
+ QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
+ MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test").toBool(), false);
+
+ MyQmlObject object2;
+ MyQmlObject object3;
+ object2.setObjectProperty(&object3);
+ object->setObjectProperty(&object2);
+
+ QCOMPARE(object->property("test").toBool(), true);
+
+ delete object;
+}
+
+void tst_qqmlecmascript::exceptionSlotProducesWarning()
+{
+ QQmlComponent component(&engine, testFileUrl("exceptionProducesWarning.qml"));
+ QString url = component.url().toString();
+
+ QString warning = component.url().toString() + ":6: Error: JS exception";
+
+ QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
+ MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
+ QVERIFY(object != 0);
+ delete object;
+}
+
+void tst_qqmlecmascript::exceptionBindingProducesWarning()
+{
+ QQmlComponent component(&engine, testFileUrl("exceptionProducesWarning2.qml"));
+ QString url = component.url().toString();
+
+ QString warning = component.url().toString() + ":5: Error: JS exception";
+
+ QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
+ MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
+ QVERIFY(object != 0);
+ delete object;
+}
+
+void tst_qqmlecmascript::compileInvalidBinding()
+{
+ // QTBUG-23387: ensure that invalid bindings don't cause a crash.
+ QQmlComponent component(&engine, testFileUrl("v8bindingException.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ delete object;
+}
+
+static int transientErrorsMsgCount = 0;
+static void transientErrorsMsgHandler(QtMsgType, const char *)
+{
+ ++transientErrorsMsgCount;
+}
+
+// Check that transient binding errors are not displayed
+void tst_qqmlecmascript::transientErrors()
+{
+ {
+ QQmlComponent component(&engine, testFileUrl("transientErrors.qml"));
+
+ transientErrorsMsgCount = 0;
+ QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ qInstallMsgHandler(old);
+
+ QCOMPARE(transientErrorsMsgCount, 0);
+
+ delete object;
+ }
+
+ // One binding erroring multiple times, but then resolving
+ {
+ QQmlComponent component(&engine, testFileUrl("transientErrors.2.qml"));
+
+ transientErrorsMsgCount = 0;
+ QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ qInstallMsgHandler(old);
+
+ QCOMPARE(transientErrorsMsgCount, 0);
+
+ delete object;
+ }
+}
+
+// Check that errors during shutdown are minimized
+void tst_qqmlecmascript::shutdownErrors()
+{
+ QQmlComponent component(&engine, testFileUrl("shutdownErrors.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ transientErrorsMsgCount = 0;
+ QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
+
+ delete object;
+
+ qInstallMsgHandler(old);
+ QCOMPARE(transientErrorsMsgCount, 0);
+}
+
+void tst_qqmlecmascript::compositePropertyType()
+{
+ QQmlComponent component(&engine, testFileUrl("compositePropertyType.qml"));
+
+ QTest::ignoreMessage(QtDebugMsg, "hello world");
+ QObject *object = qobject_cast<QObject *>(component.create());
+ delete object;
+}
+
+// QTBUG-5759
+void tst_qqmlecmascript::jsObject()
+{
+ QQmlComponent component(&engine, testFileUrl("jsObject.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test").toInt(), 92);
+
+ delete object;
+}
+
+void tst_qqmlecmascript::undefinedResetsProperty()
+{
+ {
+ QQmlComponent component(&engine, testFileUrl("undefinedResetsProperty.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("resettableProperty").toInt(), 92);
+
+ object->setProperty("setUndefined", true);
+
+ QCOMPARE(object->property("resettableProperty").toInt(), 13);
+
+ object->setProperty("setUndefined", false);
+
+ QCOMPARE(object->property("resettableProperty").toInt(), 92);
+
+ delete object;
+ }
+ {
+ QQmlComponent component(&engine, testFileUrl("undefinedResetsProperty.2.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("resettableProperty").toInt(), 19);
+
+ QMetaObject::invokeMethod(object, "doReset");
+
+ QCOMPARE(object->property("resettableProperty").toInt(), 13);
+
+ delete object;
+ }
+}
+
+// Aliases to variant properties should work
+void tst_qqmlecmascript::qtbug_22464()
+{
+ QQmlComponent component(&engine, testFileUrl("qtbug_22464.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test").toBool(), true);
+
+ delete object;
+}
+
+void tst_qqmlecmascript::qtbug_21580()
+{
+ QQmlComponent component(&engine, testFileUrl("qtbug_21580.qml"));
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test").toBool(), true);
+
+ delete object;
+}
+
+// QTBUG-6781
+void tst_qqmlecmascript::bug1()
+{
+ QQmlComponent component(&engine, testFileUrl("bug.1.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test").toInt(), 14);
+
+ object->setProperty("a", 11);
+
+ QCOMPARE(object->property("test").toInt(), 3);
+
+ object->setProperty("b", true);
+
+ QCOMPARE(object->property("test").toInt(), 9);
+
+ delete object;
+}
+
+void tst_qqmlecmascript::bug2()
+{
+ QQmlComponent component(&engine);
+ component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ delete object;
+}
+
+// Don't crash in createObject when the component has errors.
+void tst_qqmlecmascript::dynamicCreationCrash()
+{
+ QQmlComponent component(&engine, testFileUrl("dynamicCreation.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
+ QVERIFY(object != 0);
+
+ QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready");
+ QMetaObject::invokeMethod(object, "dontCrash");
+ QObject *created = object->objectProperty();
+ QVERIFY(created == 0);
+
+ delete object;
+}
+
+// ownership transferred to JS, ensure that GC runs the dtor
+void tst_qqmlecmascript::dynamicCreationOwnership()
+{
+ int dtorCount = 0;
+ int expectedDtorCount = 1; // start at 1 since we expect mdcdo to dtor too.
+
+ // allow the engine to go out of scope too.
+ {
+ QQmlEngine dcoEngine;
+ QQmlComponent component(&dcoEngine, testFileUrl("dynamicCreationOwnership.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
+ QVERIFY(mdcdo != 0);
+ mdcdo->setDtorCount(&dtorCount);
+
+ for (int i = 1; i < 105; ++i, ++expectedDtorCount) {
+ QMetaObject::invokeMethod(object, "dynamicallyCreateJsOwnedObject");
+ if (i % 90 == 0) {
+ // we do this once manually, but it should be done automatically
+ // when the engine goes out of scope (since it should gc in dtor)
+ QMetaObject::invokeMethod(object, "performGc");
+ }
+ if (i % 10 == 0) {
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
+ }
+ }
+
+ delete object;
+ }
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
+ QCOMPARE(dtorCount, expectedDtorCount);
+}
+
+void tst_qqmlecmascript::regExpBug()
+{
+ //QTBUG-9367
+ {
+ QQmlComponent component(&engine, testFileUrl("regExp.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
+ QVERIFY(object != 0);
+ QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
+ delete object;
+ }
+
+ //QTBUG-23068
+ {
+ QString err = QString(QLatin1String("%1:6 Invalid property assignment: regular expression expected; use /pattern/ syntax\n")).arg(testFileUrl("regExp.2.qml").toString());
+ QQmlComponent component(&engine, testFileUrl("regExp.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, v8::Handle<v8::Object> o, const char *source)
+{
+ QString functionSource = QLatin1String("(function(object) { return ") +
+ QLatin1String(source) + QLatin1String(" })");
+ v8::TryCatch tc;
+ v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
+ if (tc.HasCaught())
+ return false;
+ v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
+ if (function.IsEmpty())
+ return false;
+ v8::Handle<v8::Value> args[] = { o };
+ function->Call(engine->global(), 1, args);
+ return tc.HasCaught();
+}
+
+static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
+ const char *source, v8::Handle<v8::Value> result)
+{
+ QString functionSource = QLatin1String("(function(object) { return ") +
+ QLatin1String(source) + QLatin1String(" })");
+ v8::TryCatch tc;
+ v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
+ if (tc.HasCaught())
+ return false;
+ v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
+ if (function.IsEmpty())
+ return false;
+ v8::Handle<v8::Value> args[] = { o };
+
+ v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
+
+ if (tc.HasCaught())
+ return false;
+
+ return value->StrictEquals(result);
+}
+
+static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
+ const char *source)
+{
+ QString functionSource = QLatin1String("(function(object) { return ") +
+ QLatin1String(source) + QLatin1String(" })");
+ v8::TryCatch tc;
+ v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
+ if (tc.HasCaught())
+ return v8::Handle<v8::Value>();
+ v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
+ if (function.IsEmpty())
+ return v8::Handle<v8::Value>();
+ v8::Handle<v8::Value> args[] = { o };
+
+ v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
+
+ if (tc.HasCaught())
+ return v8::Handle<v8::Value>();
+ return value;
+}
+
+#define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
+#define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
+#define EVALUATE(source) evaluate(engine, object, source)
+
+void tst_qqmlecmascript::callQtInvokables()
+{
+ MyInvokableObject o;
+
+ QQmlEngine qmlengine;
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(&qmlengine);
+
+ QV8Engine *engine = ep->v8engine();
+
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(engine->context());
+
+ v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
+
+ // Non-existent methods
+ o.reset();
+ QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), -1);
+ QCOMPARE(o.actuals().count(), 0);
+
+ o.reset();
+ QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), -1);
+ QCOMPARE(o.actuals().count(), 0);
+
+ // Insufficient arguments
+ o.reset();
+ QVERIFY(EVALUATE_ERROR("object.method_int()"));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), -1);
+ QCOMPARE(o.actuals().count(), 0);
+
+ o.reset();
+ QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), -1);
+ QCOMPARE(o.actuals().count(), 0);
+
+ // Excessive arguments
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 8);
+ QCOMPARE(o.actuals().count(), 1);
+ QCOMPARE(o.actuals().at(0), QVariant(10));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 9);
+ QCOMPARE(o.actuals().count(), 2);
+ QCOMPARE(o.actuals().at(0), QVariant(10));
+ QCOMPARE(o.actuals().at(1), QVariant(11));
+
+ // Test return types
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 0);
+ QCOMPARE(o.actuals().count(), 0);
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 1);
+ QCOMPARE(o.actuals().count(), 0);
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 2);
+ QCOMPARE(o.actuals().count(), 0);
+
+ o.reset();
+ {
+ v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
+ QVERIFY(!ret.IsEmpty());
+ QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 3);
+ QCOMPARE(o.actuals().count(), 0);
+ }
+
+ o.reset();
+ {
+ v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
+ QCOMPARE(engine->toQObject(ret), (QObject *)&o);
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 4);
+ QCOMPARE(o.actuals().count(), 0);
+ }
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 5);
+ QCOMPARE(o.actuals().count(), 0);
+
+ o.reset();
+ {
+ v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
+ QVERIFY(ret->IsString());
+ QCOMPARE(engine->toString(ret), QString("Hello world"));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 6);
+ QCOMPARE(o.actuals().count(), 0);
+ }
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 7);
+ QCOMPARE(o.actuals().count(), 0);
+
+ // Test arg types
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 8);
+ QCOMPARE(o.actuals().count(), 1);
+ QCOMPARE(o.actuals().at(0), QVariant(94));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 8);
+ QCOMPARE(o.actuals().count(), 1);
+ QCOMPARE(o.actuals().at(0), QVariant(94));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 8);
+ QCOMPARE(o.actuals().count(), 1);
+ QCOMPARE(o.actuals().at(0), QVariant(0));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 8);
+ QCOMPARE(o.actuals().count(), 1);
+ QCOMPARE(o.actuals().at(0), QVariant(0));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 8);
+ QCOMPARE(o.actuals().count(), 1);
+ QCOMPARE(o.actuals().at(0), QVariant(0));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 8);
+ QCOMPARE(o.actuals().count(), 1);
+ QCOMPARE(o.actuals().at(0), QVariant(0));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 9);
+ QCOMPARE(o.actuals().count(), 2);
+ QCOMPARE(o.actuals().at(0), QVariant(122));
+ QCOMPARE(o.actuals().at(1), QVariant(9));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 10);
+ QCOMPARE(o.actuals().count(), 1);
+ QCOMPARE(o.actuals().at(0), QVariant(94.3));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 10);
+ QCOMPARE(o.actuals().count(), 1);
+ QCOMPARE(o.actuals().at(0), QVariant(94.3));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 10);
+ QCOMPARE(o.actuals().count(), 1);
+ QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 10);
+ QCOMPARE(o.actuals().count(), 1);
+ QCOMPARE(o.actuals().at(0), QVariant(0));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 10);
+ QCOMPARE(o.actuals().count(), 1);
+ QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 10);
+ QCOMPARE(o.actuals().count(), 1);
+ QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 11);
+ QCOMPARE(o.actuals().count(), 1);
+ QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 11);
+ QCOMPARE(o.actuals().count(), 1);
+ QCOMPARE(o.actuals().at(0), QVariant("19"));
+
+ o.reset();
+ {
+ QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
+ QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 11);
+ QCOMPARE(o.actuals().count(), 1);
+ QCOMPARE(o.actuals().at(0), QVariant(expected));
+ }
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 11);
+ QCOMPARE(o.actuals().count(), 1);
+ QCOMPARE(o.actuals().at(0), QVariant(QString()));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 11);
+ QCOMPARE(o.actuals().count(), 1);
+ QCOMPARE(o.actuals().at(0), QVariant(QString()));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 12);
+ QCOMPARE(o.actuals().count(), 1);
+ QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 12);
+ QCOMPARE(o.actuals().count(), 1);
+ QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 12);
+ QCOMPARE(o.actuals().count(), 1);
+ QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 12);
+ QCOMPARE(o.actuals().count(), 1);
+ QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 12);
+ QCOMPARE(o.actuals().count(), 1);
+ QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 12);
+ QCOMPARE(o.actuals().count(), 1);
+ QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 13);
+ QCOMPARE(o.actuals().count(), 1);
+ QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 13);
+ QCOMPARE(o.actuals().count(), 1);
+ QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 13);
+ QCOMPARE(o.actuals().count(), 1);
+ QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 13);
+ QCOMPARE(o.actuals().count(), 1);
+ QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 13);
+ QCOMPARE(o.actuals().count(), 1);
+ QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 14);
+ QCOMPARE(o.actuals().count(), 1);
+ QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 14);
+ QCOMPARE(o.actuals().count(), 1);
+ QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 14);
+ QCOMPARE(o.actuals().count(), 1);
+ QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 14);
+ QCOMPARE(o.actuals().count(), 1);
+ QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 15);
+ QCOMPARE(o.actuals().count(), 2);
+ QCOMPARE(o.actuals().at(0), QVariant(4));
+ QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 15);
+ QCOMPARE(o.actuals().count(), 2);
+ QCOMPARE(o.actuals().at(0), QVariant(8));
+ QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 15);
+ QCOMPARE(o.actuals().count(), 2);
+ QCOMPARE(o.actuals().at(0), QVariant(3));
+ QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 15);
+ QCOMPARE(o.actuals().count(), 2);
+ QCOMPARE(o.actuals().at(0), QVariant(44));
+ QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
+
+ o.reset();
+ QVERIFY(EVALUATE_ERROR("object.method_overload()"));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), -1);
+ QCOMPARE(o.actuals().count(), 0);
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 16);
+ QCOMPARE(o.actuals().count(), 1);
+ QCOMPARE(o.actuals().at(0), QVariant(10));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 17);
+ QCOMPARE(o.actuals().count(), 2);
+ QCOMPARE(o.actuals().at(0), QVariant(10));
+ QCOMPARE(o.actuals().at(1), QVariant(11));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 18);
+ QCOMPARE(o.actuals().count(), 1);
+ QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 19);
+ QCOMPARE(o.actuals().count(), 1);
+ QCOMPARE(o.actuals().at(0), QVariant(9));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 20);
+ QCOMPARE(o.actuals().count(), 2);
+ QCOMPARE(o.actuals().at(0), QVariant(10));
+ QCOMPARE(o.actuals().at(1), QVariant(19));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 20);
+ QCOMPARE(o.actuals().count(), 2);
+ QCOMPARE(o.actuals().at(0), QVariant(10));
+ QCOMPARE(o.actuals().at(1), QVariant(13));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), -3);
+ QCOMPARE(o.actuals().count(), 1);
+ QCOMPARE(o.actuals().at(0), QVariant(9));
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 21);
+ QCOMPARE(o.actuals().count(), 2);
+ QCOMPARE(o.actuals().at(0), QVariant(9));
+ QCOMPARE(o.actuals().at(1), QVariant());
+
+ o.reset();
+ QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
+ QCOMPARE(o.error(), false);
+ QCOMPARE(o.invoked(), 21);
+ QCOMPARE(o.actuals().count(), 2);
+ QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
+ QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
+}
+
+// QTBUG-13047 (check that you can pass registered object types as args)
+void tst_qqmlecmascript::invokableObjectArg()
+{
+ QQmlComponent component(&engine, testFileUrl("invokableObjectArg.qml"));
+
+ QObject *o = component.create();
+ QVERIFY(o);
+ MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
+ QVERIFY(qmlobject);
+ QCOMPARE(qmlobject->myinvokableObject, qmlobject);
+
+ delete o;
+}
+
+// QTBUG-13047 (check that you can return registered object types from methods)
+void tst_qqmlecmascript::invokableObjectRet()
+{
+ QQmlComponent component(&engine, testFileUrl("invokableObjectRet.qml"));
+
+ QObject *o = component.create();
+ QVERIFY(o);
+ QCOMPARE(o->property("test").toBool(), true);
+ delete o;
+}
+
+// QTBUG-5675
+void tst_qqmlecmascript::listToVariant()
+{
+ QQmlComponent component(&engine, testFileUrl("listToVariant.qml"));
+
+ MyQmlContainer container;
+
+ QQmlContext context(engine.rootContext());
+ context.setContextObject(&container);
+
+ QObject *object = component.create(&context);
+ QVERIFY(object != 0);
+
+ QVariant v = object->property("test");
+ QCOMPARE(v.userType(), qMetaTypeId<QQmlListReference>());
+ QVERIFY(qvariant_cast<QQmlListReference>(v).object() == &container);
+
+ delete object;
+}
+
+// QTBUG-16316
+Q_DECLARE_METATYPE(QQmlListProperty<MyQmlObject>)
+void tst_qqmlecmascript::listAssignment()
+{
+ QQmlComponent component(&engine, testFileUrl("listAssignment.qml"));
+ QObject *obj = component.create();
+ QCOMPARE(obj->property("list1length").toInt(), 2);
+ QQmlListProperty<MyQmlObject> list1 = obj->property("list1").value<QQmlListProperty<MyQmlObject> >();
+ QQmlListProperty<MyQmlObject> list2 = obj->property("list2").value<QQmlListProperty<MyQmlObject> >();
+ QCOMPARE(list1.count(&list1), list2.count(&list2));
+ QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
+ QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
+ delete obj;
+}
+
+// QTBUG-7957
+void tst_qqmlecmascript::multiEngineObject()
+{
+ MyQmlObject obj;
+ obj.setStringProperty("Howdy planet");
+
+ QQmlEngine e1;
+ e1.rootContext()->setContextProperty("thing", &obj);
+ QQmlComponent c1(&e1, testFileUrl("multiEngineObject.qml"));
+
+ QQmlEngine e2;
+ e2.rootContext()->setContextProperty("thing", &obj);
+ QQmlComponent c2(&e2, testFileUrl("multiEngineObject.qml"));
+
+ QObject *o1 = c1.create();
+ QObject *o2 = c2.create();
+
+ QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
+ QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
+
+ delete o2;
+ delete o1;
+}
+
+// Test that references to QObjects are cleanup when the object is destroyed
+void tst_qqmlecmascript::deletedObject()
+{
+ QQmlComponent component(&engine, testFileUrl("deletedObject.qml"));
+
+ QObject *object = component.create();
+
+ QCOMPARE(object->property("test1").toBool(), true);
+ QCOMPARE(object->property("test2").toBool(), true);
+ QCOMPARE(object->property("test3").toBool(), true);
+ QCOMPARE(object->property("test4").toBool(), true);
+
+ delete object;
+}
+
+void tst_qqmlecmascript::attachedPropertyScope()
+{
+ QQmlComponent component(&engine, testFileUrl("attachedPropertyScope.qml"));
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ MyQmlAttachedObject *attached =
+ qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
+ QVERIFY(attached != 0);
+
+ QCOMPARE(object->property("value2").toInt(), 0);
+
+ attached->emitMySignal();
+
+ QCOMPARE(object->property("value2").toInt(), 9);
+
+ delete object;
+}
+
+void tst_qqmlecmascript::scriptConnect()
+{
+ {
+ QQmlComponent component(&engine, testFileUrl("scriptConnect.1.qml"));
+
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test").toBool(), false);
+ emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
+ QCOMPARE(object->property("test").toBool(), true);
+
+ delete object;
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("scriptConnect.2.qml"));
+
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test").toBool(), false);
+ emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
+ QCOMPARE(object->property("test").toBool(), true);
+
+ delete object;
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("scriptConnect.3.qml"));
+
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test").toBool(), false);
+ emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
+ QCOMPARE(object->property("test").toBool(), true);
+
+ delete object;
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("scriptConnect.4.qml"));
+
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->methodCalled(), false);
+ emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
+ QCOMPARE(object->methodCalled(), true);
+
+ delete object;
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("scriptConnect.5.qml"));
+
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->methodCalled(), false);
+ emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
+ QCOMPARE(object->methodCalled(), true);
+
+ delete object;
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("scriptConnect.6.qml"));
+
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test").toInt(), 0);
+ emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
+ QCOMPARE(object->property("test").toInt(), 2);
+
+ delete object;
+ }
+}
+
+void tst_qqmlecmascript::scriptDisconnect()
+{
+ {
+ QQmlComponent component(&engine, testFileUrl("scriptDisconnect.1.qml"));
+
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test").toInt(), 0);
+ emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
+ QCOMPARE(object->property("test").toInt(), 1);
+ emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
+ QCOMPARE(object->property("test").toInt(), 2);
+ emit object->basicSignal();
+ QCOMPARE(object->property("test").toInt(), 2);
+ emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
+ QCOMPARE(object->property("test").toInt(), 2);
+
+ delete object;
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("scriptDisconnect.2.qml"));
+
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test").toInt(), 0);
+ emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
+ QCOMPARE(object->property("test").toInt(), 1);
+ emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
+ QCOMPARE(object->property("test").toInt(), 2);
+ emit object->basicSignal();
+ QCOMPARE(object->property("test").toInt(), 2);
+ emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
+ QCOMPARE(object->property("test").toInt(), 2);
+
+ delete object;
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("scriptDisconnect.3.qml"));
+
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test").toInt(), 0);
+ emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
+ QCOMPARE(object->property("test").toInt(), 1);
+ emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
+ QCOMPARE(object->property("test").toInt(), 2);
+ emit object->basicSignal();
+ QCOMPARE(object->property("test").toInt(), 2);
+ emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
+ QCOMPARE(object->property("test").toInt(), 3);
+
+ delete object;
+ }
+ {
+ QQmlComponent component(&engine, testFileUrl("scriptDisconnect.4.qml"));
+
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test").toInt(), 0);
+ emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
+ QCOMPARE(object->property("test").toInt(), 1);
+ emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
+ QCOMPARE(object->property("test").toInt(), 2);
+ emit object->basicSignal();
+ QCOMPARE(object->property("test").toInt(), 2);
+ emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
+ QCOMPARE(object->property("test").toInt(), 3);
+
+ delete object;
+ }
+}
+
+class OwnershipObject : public QObject
+{
+ Q_OBJECT
+public:
+ OwnershipObject() { object = new QObject; }
+
+ QPointer<QObject> object;
+
+public slots:
+ QObject *getObject() { return object; }
+};
+
+void tst_qqmlecmascript::ownership()
+{
+ OwnershipObject own;
+ QQmlContext *context = new QQmlContext(engine.rootContext());
+ context->setContextObject(&own);
+
+ {
+ QQmlComponent component(&engine, testFileUrl("ownership.qml"));
+
+ QVERIFY(own.object != 0);
+
+ QObject *object = component.create(context);
+
+ engine.collectGarbage();
+
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
+
+ QVERIFY(own.object == 0);
+
+ delete object;
+ }
+
+ own.object = new QObject(&own);
+
+ {
+ QQmlComponent component(&engine, testFileUrl("ownership.qml"));
+
+ QVERIFY(own.object != 0);
+
+ QObject *object = component.create(context);
+
+ engine.collectGarbage();
+
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
+
+ QVERIFY(own.object != 0);
+
+ delete object;
+ }
+
+ delete context;
+}
+
+class CppOwnershipReturnValue : public QObject
+{
+ Q_OBJECT
+public:
+ CppOwnershipReturnValue() : value(0) {}
+ ~CppOwnershipReturnValue() { delete value; }
+
+ Q_INVOKABLE QObject *create() {
+ value = new QObject;
+ QQmlEngine::setObjectOwnership(value, QQmlEngine::CppOwnership);
+ return value;
+ }
+
+ Q_INVOKABLE MyQmlObject *createQmlObject() {
+ MyQmlObject *rv = new MyQmlObject;
+ value = rv;
+ return rv;
+ }
+
+ QPointer<QObject> value;
+};
+
+// QTBUG-15695.
+// Test setObjectOwnership(CppOwnership) works even when there is no QQmlData
+void tst_qqmlecmascript::cppOwnershipReturnValue()
+{
+ CppOwnershipReturnValue source;
+
+ {
+ QQmlEngine engine;
+ engine.rootContext()->setContextProperty("source", &source);
+
+ QVERIFY(source.value == 0);
+
+ QQmlComponent component(&engine);
+ component.setData("import QtQuick 2.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
+
+ QObject *object = component.create();
+
+ QVERIFY(object != 0);
+ QVERIFY(source.value != 0);
+
+ delete object;
+ }
+
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
+
+ QVERIFY(source.value != 0);
+}
+
+// QTBUG-15697
+void tst_qqmlecmascript::ownershipCustomReturnValue()
+{
+ CppOwnershipReturnValue source;
+
+ {
+ QQmlEngine engine;
+ engine.rootContext()->setContextProperty("source", &source);
+
+ QVERIFY(source.value == 0);
+
+ QQmlComponent component(&engine);
+ component.setData("import QtQuick 2.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
+
+ QObject *object = component.create();
+
+ QVERIFY(object != 0);
+ QVERIFY(source.value != 0);
+
+ delete object;
+ }
+
+ engine.collectGarbage();
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
+
+ QVERIFY(source.value == 0);
+}
+
+class QListQObjectMethodsObject : public QObject
+{
+ Q_OBJECT
+public:
+ QListQObjectMethodsObject() {
+ m_objects.append(new MyQmlObject());
+ m_objects.append(new MyQmlObject());
+ }
+
+ ~QListQObjectMethodsObject() {
+ qDeleteAll(m_objects);
+ }
+
+public slots:
+ QList<QObject *> getObjects() { return m_objects; }
+
+private:
+ QList<QObject *> m_objects;
+};
+
+// Tests that returning a QList<QObject*> from a method works
+void tst_qqmlecmascript::qlistqobjectMethods()
+{
+ QListQObjectMethodsObject obj;
+ QQmlContext *context = new QQmlContext(engine.rootContext());
+ context->setContextObject(&obj);
+
+ QQmlComponent component(&engine, testFileUrl("qlistqobjectMethods.qml"));
+
+ QObject *object = component.create(context);
+
+ QCOMPARE(object->property("test").toInt(), 2);
+ QCOMPARE(object->property("test2").toBool(), true);
+
+ delete object;
+ delete context;
+}
+
+// QTBUG-9205
+void tst_qqmlecmascript::strictlyEquals()
+{
+ QQmlComponent component(&engine, testFileUrl("strictlyEquals.qml"));
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test1").toBool(), true);
+ QCOMPARE(object->property("test2").toBool(), true);
+ QCOMPARE(object->property("test3").toBool(), true);
+ QCOMPARE(object->property("test4").toBool(), true);
+ QCOMPARE(object->property("test5").toBool(), true);
+ QCOMPARE(object->property("test6").toBool(), true);
+ QCOMPARE(object->property("test7").toBool(), true);
+ QCOMPARE(object->property("test8").toBool(), true);
+
+ delete object;
+}
+
+void tst_qqmlecmascript::compiled()
+{
+ QQmlComponent component(&engine, testFileUrl("compiled.qml"));
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test1").toReal(), qreal(15.7));
+ QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
+ QCOMPARE(object->property("test3").toBool(), true);
+ QCOMPARE(object->property("test4").toBool(), false);
+ QCOMPARE(object->property("test5").toBool(), false);
+ QCOMPARE(object->property("test6").toBool(), true);
+
+ QCOMPARE(object->property("test7").toInt(), 185);
+ QCOMPARE(object->property("test8").toInt(), 167);
+ QCOMPARE(object->property("test9").toBool(), true);
+ QCOMPARE(object->property("test10").toBool(), false);
+ QCOMPARE(object->property("test11").toBool(), false);
+ QCOMPARE(object->property("test12").toBool(), true);
+
+ QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
+ QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
+ QCOMPARE(object->property("test15").toBool(), false);
+ QCOMPARE(object->property("test16").toBool(), true);
+
+ QCOMPARE(object->property("test17").toInt(), 5);
+ QCOMPARE(object->property("test18").toReal(), qreal(176));
+ QCOMPARE(object->property("test19").toInt(), 7);
+ QCOMPARE(object->property("test20").toReal(), qreal(6.7));
+ QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
+ QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
+ QCOMPARE(object->property("test23").toBool(), true);
+ QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
+ QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
+
+ delete object;
+}
+
+// Test that numbers assigned in bindings as strings work consistently
+void tst_qqmlecmascript::numberAssignment()
+{
+ QQmlComponent component(&engine, testFileUrl("numberAssignment.qml"));
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
+ QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
+ QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
+ QCOMPARE(object->property("test3"), QVariant((qreal)6));
+ QCOMPARE(object->property("test4"), QVariant((qreal)6));
+
+ QCOMPARE(object->property("test5"), QVariant((int)7));
+ QCOMPARE(object->property("test6"), QVariant((int)7));
+ QCOMPARE(object->property("test7"), QVariant((int)6));
+ QCOMPARE(object->property("test8"), QVariant((int)6));
+
+ QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
+ QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
+ QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
+ QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
+
+ delete object;
+}
+
+void tst_qqmlecmascript::propertySplicing()
+{
+ QQmlComponent component(&engine, testFileUrl("propertySplicing.qml"));
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test").toBool(), true);
+
+ delete object;
+}
+
+// QTBUG-16683
+void tst_qqmlecmascript::signalWithUnknownTypes()
+{
+ QQmlComponent component(&engine, testFileUrl("signalWithUnknownTypes.qml"));
+
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ MyQmlObject::MyType type;
+ type.value = 0x8971123;
+ emit object->signalWithUnknownType(type);
+
+ MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
+
+ QCOMPARE(result.value, type.value);
+
+
+ delete object;
+}
+
+void tst_qqmlecmascript::signalWithJSValueInVariant_data()
+{
+ QTest::addColumn<QString>("expression");
+ QTest::addColumn<QString>("compare");
+
+ QString compareStrict("(function(a, b) { return a === b; })");
+ QTest::newRow("true") << "true" << compareStrict;
+ QTest::newRow("undefined") << "undefined" << compareStrict;
+ QTest::newRow("null") << "null" << compareStrict;
+ QTest::newRow("123") << "123" << compareStrict;
+ QTest::newRow("'ciao'") << "'ciao'" << compareStrict;
+
+ QString comparePropertiesStrict(
+ "(function(a, b) {"
+ " if (typeof b != 'object')"
+ " return a === b;"
+ " var props = Object.getOwnPropertyNames(b);"
+ " for (var i = 0; i < props.length; ++i) {"
+ " var p = props[i];"
+ " return arguments.callee(a[p], b[p]);"
+ " }"
+ "})");
+ QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict;
+ QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict;
+}
+
+void tst_qqmlecmascript::signalWithJSValueInVariant()
+{
+ QFETCH(QString, expression);
+ QFETCH(QString, compare);
+
+ QQmlComponent component(&engine, testFileUrl("signalWithJSValueInVariant.qml"));
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
+ QVERIFY(object != 0);
+
+ QJSValue value = engine.evaluate(expression);
+ QVERIFY(!engine.hasUncaughtException());
+ object->setProperty("expression", expression);
+ object->setProperty("compare", compare);
+ object->setProperty("pass", false);
+
+ emit object->signalWithVariant(QVariant::fromValue(value));
+ QVERIFY(object->property("pass").toBool());
+}
+
+void tst_qqmlecmascript::signalWithJSValueInVariant_twoEngines_data()
+{
+ signalWithJSValueInVariant_data();
+}
+
+void tst_qqmlecmascript::signalWithJSValueInVariant_twoEngines()
+{
+ QFETCH(QString, expression);
+ QFETCH(QString, compare);
+
+ QQmlComponent component(&engine, testFileUrl("signalWithJSValueInVariant.qml"));
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
+ QVERIFY(object != 0);
+
+ QJSEngine engine2;
+ QJSValue value = engine2.evaluate(expression);
+ QVERIFY(!engine2.hasUncaughtException());
+ object->setProperty("expression", expression);
+ object->setProperty("compare", compare);
+ object->setProperty("pass", false);
+
+ QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine.");
+ emit object->signalWithVariant(QVariant::fromValue(value));
+ QVERIFY(!object->property("pass").toBool());
+}
+
+void tst_qqmlecmascript::signalWithQJSValue_data()
+{
+ signalWithJSValueInVariant_data();
+}
+
+void tst_qqmlecmascript::signalWithQJSValue()
+{
+ QFETCH(QString, expression);
+ QFETCH(QString, compare);
+
+ QQmlComponent component(&engine, testFileUrl("signalWithQJSValue.qml"));
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
+ QVERIFY(object != 0);
+
+ QJSValue value = engine.evaluate(expression);
+ QVERIFY(!engine.hasUncaughtException());
+ object->setProperty("expression", expression);
+ object->setProperty("compare", compare);
+ object->setProperty("pass", false);
+
+ emit object->signalWithQJSValue(value);
+
+ QVERIFY(object->property("pass").toBool());
+ QVERIFY(object->qjsvalue().strictlyEquals(value));
+}
+
+void tst_qqmlecmascript::moduleApi_data()
+{
+ QTest::addColumn<QUrl>("testfile");
+ QTest::addColumn<QString>("errorMessage");
+ QTest::addColumn<QStringList>("warningMessages");
+ QTest::addColumn<QStringList>("readProperties");
+ QTest::addColumn<QVariantList>("readExpectedValues");
+ QTest::addColumn<QStringList>("writeProperties");
+ QTest::addColumn<QVariantList>("writeValues");
+ QTest::addColumn<QStringList>("readBackProperties");
+ QTest::addColumn<QVariantList>("readBackExpectedValues");
+
+ QTest::newRow("qobject, register + read + method")
+ << testFileUrl("moduleapi/qobjectModuleApi.qml")
+ << QString()
+ << QStringList()
+ << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
+ << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
+ << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
+ << QStringList()
+ << QVariantList()
+ << QStringList()
+ << QVariantList();
+
+ QTest::newRow("script, register + read")
+ << testFileUrl("moduleapi/scriptModuleApi.qml")
+ << QString()
+ << QStringList()
+ << (QStringList() << "scriptTest")
+ << (QVariantList() << 13)
+ << QStringList()
+ << QVariantList()
+ << QStringList()
+ << QVariantList();
+
+ QTest::newRow("qobject, caching + read")
+ << testFileUrl("moduleapi/qobjectModuleApiCaching.qml")
+ << QString()
+ << QStringList()
+ << (QStringList() << "existingUriTest" << "qobjectParentedTest")
+ << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
+ << QStringList()
+ << QVariantList()
+ << QStringList()
+ << QVariantList();
+
+ QTest::newRow("script, caching + read")
+ << testFileUrl("moduleapi/scriptModuleApiCaching.qml")
+ << QString()
+ << QStringList()
+ << (QStringList() << "scriptTest")
+ << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
+ << QStringList()
+ << QVariantList()
+ << QStringList()
+ << QVariantList();
+
+ QTest::newRow("qobject, writing + readonly constraints")
+ << testFileUrl("moduleapi/qobjectModuleApiWriting.qml")
+ << QString()
+ << (QStringList() << QString(QLatin1String("file://") + testFileUrl("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
+ << (QStringList() << "readOnlyProperty" << "writableProperty")
+ << (QVariantList() << 20 << 50)
+ << (QStringList() << "firstProperty" << "writableProperty")
+ << (QVariantList() << 30 << 30)
+ << (QStringList() << "readOnlyProperty" << "writableProperty")
+ << (QVariantList() << 20 << 30);
+
+ QTest::newRow("script, writing + readonly constraints")
+ << testFileUrl("moduleapi/scriptModuleApiWriting.qml")
+ << QString()
+ << (QStringList() << QString(QLatin1String("file://") + testFileUrl("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
+ << (QStringList() << "readBack" << "unchanged")
+ << (QVariantList() << 13 << 42)
+ << (QStringList() << "firstProperty" << "secondProperty")
+ << (QVariantList() << 30 << 30)
+ << (QStringList() << "readBack" << "unchanged")
+ << (QVariantList() << 30 << 42);
+
+ QTest::newRow("qobject module API enum values in JS")
+ << testFileUrl("moduleapi/qobjectModuleApiEnums.qml")
+ << QString()
+ << QStringList()
+ << (QStringList() << "enumValue" << "enumMethod")
+ << (QVariantList() << 42 << 30)
+ << QStringList()
+ << QVariantList()
+ << QStringList()
+ << QVariantList();
+
+ QTest::newRow("qobject, invalid major version fail")
+ << testFileUrl("moduleapi/moduleApiMajorVersionFail.qml")
+ << QString("QQmlComponent: Component is not ready")
+ << QStringList()
+ << QStringList()
+ << QVariantList()
+ << QStringList()
+ << QVariantList()
+ << QStringList()
+ << QVariantList();
+
+ QTest::newRow("qobject, invalid minor version fail")
+ << testFileUrl("moduleapi/moduleApiMinorVersionFail.qml")
+ << QString("QQmlComponent: Component is not ready")
+ << QStringList()
+ << QStringList()
+ << QVariantList()
+ << QStringList()
+ << QVariantList()
+ << QStringList()
+ << QVariantList();
+}
+
+void tst_qqmlecmascript::moduleApi()
+{
+ QFETCH(QUrl, testfile);
+ QFETCH(QString, errorMessage);
+ QFETCH(QStringList, warningMessages);
+ QFETCH(QStringList, readProperties);
+ QFETCH(QVariantList, readExpectedValues);
+ QFETCH(QStringList, writeProperties);
+ QFETCH(QVariantList, writeValues);
+ QFETCH(QStringList, readBackProperties);
+ QFETCH(QVariantList, readBackExpectedValues);
+
+ QQmlComponent component(&engine, testfile);
+
+ if (!errorMessage.isEmpty())
+ QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
+
+ if (warningMessages.size())
+ foreach (const QString &warning, warningMessages)
+ QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
+
+ QObject *object = component.create();
+ if (!errorMessage.isEmpty()) {
+ QVERIFY(object == 0);
+ } else {
+ QVERIFY(object != 0);
+ for (int i = 0; i < readProperties.size(); ++i)
+ QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
+ for (int i = 0; i < writeProperties.size(); ++i)
+ QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
+ for (int i = 0; i < readBackProperties.size(); ++i)
+ QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
+ delete object;
+ }
+}
+
+void tst_qqmlecmascript::importScripts_data()
+{
+ QTest::addColumn<QUrl>("testfile");
+ QTest::addColumn<QString>("errorMessage");
+ QTest::addColumn<QStringList>("warningMessages");
+ QTest::addColumn<QStringList>("propertyNames");
+ QTest::addColumn<QVariantList>("propertyValues");
+
+ QTest::newRow("basic functionality")
+ << testFileUrl("jsimport/testImport.qml")
+ << QString()
+ << QStringList()
+ << (QStringList() << QLatin1String("importedScriptStringValue")
+ << QLatin1String("importedScriptFunctionValue")
+ << QLatin1String("importedModuleAttachedPropertyValue")
+ << QLatin1String("importedModuleEnumValue"))
+ << (QVariantList() << QVariant(QLatin1String("Hello, World!"))
+ << QVariant(20)
+ << QVariant(19)
+ << QVariant(2));
+
+ QTest::newRow("import scoping")
+ << testFileUrl("jsimport/testImportScoping.qml")
+ << QString()
+ << QStringList()
+ << (QStringList() << QLatin1String("componentError"))
+ << (QVariantList() << QVariant(5));
+
+ QTest::newRow("parent scope shouldn't be inherited by import with imports")
+ << testFileUrl("jsimportfail/failOne.qml")
+ << QString()
+ << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined")))
+ << (QStringList() << QLatin1String("importScriptFunctionValue"))
+ << (QVariantList() << QVariant(QString()));
+
+ QTest::newRow("javascript imports in an import should be private to the import scope")
+ << testFileUrl("jsimportfail/failTwo.qml")
+ << QString()
+ << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs")))
+ << (QStringList() << QLatin1String("importScriptFunctionValue"))
+ << (QVariantList() << QVariant(QString()));
+
+ QTest::newRow("module imports in an import should be private to the import scope")
+ << testFileUrl("jsimportfail/failThree.qml")
+ << QString()
+ << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined")))
+ << (QStringList() << QLatin1String("importedModuleAttachedPropertyValue"))
+ << (QVariantList() << QVariant(false));
+
+ QTest::newRow("typenames in an import should be private to the import scope")
+ << testFileUrl("jsimportfail/failFour.qml")
+ << QString()
+ << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest")))
+ << (QStringList() << QLatin1String("importedModuleEnumValue"))
+ << (QVariantList() << QVariant(0));
+
+ QTest::newRow("import with imports has it's own activation scope")
+ << testFileUrl("jsimportfail/failFive.qml")
+ << QString()
+ << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component")))
+ << (QStringList() << QLatin1String("componentError"))
+ << (QVariantList() << QVariant(0));
+
+ QTest::newRow("import pragma library script")
+ << testFileUrl("jsimport/testImportPragmaLibrary.qml")
+ << QString()
+ << QStringList()
+ << (QStringList() << QLatin1String("testValue"))
+ << (QVariantList() << QVariant(31));
+
+ QTest::newRow("pragma library imports shouldn't inherit parent imports or scope")
+ << testFileUrl("jsimportfail/testImportPragmaLibrary.qml")
+ << QString()
+ << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component")))
+ << (QStringList() << QLatin1String("testValue"))
+ << (QVariantList() << QVariant(0));
+
+ QTest::newRow("import pragma library script which has an import")
+ << testFileUrl("jsimport/testImportPragmaLibraryWithImports.qml")
+ << QString()
+ << QStringList()
+ << (QStringList() << QLatin1String("testValue"))
+ << (QVariantList() << QVariant(55));
+
+ QTest::newRow("import pragma library script which has a pragma library import")
+ << testFileUrl("jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml")
+ << QString()
+ << QStringList()
+ << (QStringList() << QLatin1String("testValue"))
+ << (QVariantList() << QVariant(18));
+
+ QTest::newRow("import module api into js import")
+ << testFileUrl("jsimport/testImportModuleApi.qml")
+ << QString()
+ << QStringList()
+ << (QStringList() << QLatin1String("testValue"))
+ << (QVariantList() << QVariant(20));
+}
+
+void tst_qqmlecmascript::importScripts()
+{
+ QFETCH(QUrl, testfile);
+ QFETCH(QString, errorMessage);
+ QFETCH(QStringList, warningMessages);
+ QFETCH(QStringList, propertyNames);
+ QFETCH(QVariantList, propertyValues);
+
+ QQmlComponent component(&engine, testfile);
+
+ if (!errorMessage.isEmpty())
+ QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
+
+ if (warningMessages.size())
+ foreach (const QString &warning, warningMessages)
+ QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
+
+ QObject *object = component.create();
+ if (!errorMessage.isEmpty()) {
+ QVERIFY(object == 0);
+ } else {
+ QVERIFY(object != 0);
+ for (int i = 0; i < propertyNames.size(); ++i)
+ QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
+ delete object;
+ }
+}
+
+void tst_qqmlecmascript::scarceResources_other()
+{
+ /* These tests require knowledge of state, since we test values after
+ performing signal or function invocation. */
+
+ QPixmap origPixmap(100, 100);
+ origPixmap.fill(Qt::blue);
+ QString srp_name, expectedWarning;
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(&engine);
+ ScarceResourceObject *eo = 0;
+ QObject *srsc = 0;
+ QObject *object = 0;
+
+ /* property var semantics */
+
+ // test that scarce resources are handled properly in signal invocation
+ QQmlComponent varComponentTen(&engine, testFileUrl("scarceResourceSignal.var.qml"));
+ object = varComponentTen.create();
+ srsc = object->findChild<QObject*>("srsc");
+ QVERIFY(srsc);
+ QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
+ QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
+ eo = qobject_cast<ScarceResourceObject*>(QQmlProperty::read(object, "a").value<QObject*>());
+ QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
+ QMetaObject::invokeMethod(srsc, "testSignal");
+ QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
+ QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
+ eo = qobject_cast<ScarceResourceObject*>(QQmlProperty::read(object, "a").value<QObject*>());
+ QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
+ QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
+ QVERIFY(srsc->property("scarceResourceCopy").isValid());
+ QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
+ eo = qobject_cast<ScarceResourceObject*>(QQmlProperty::read(object, "a").value<QObject*>());
+ QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
+ QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
+ delete object;
+
+ // 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->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.
+ QMetaObject::invokeMethod(object, "retrieveScarceResource");
+ QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
+ QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
+ eo = qobject_cast<ScarceResourceObject*>(QQmlProperty::read(object, "a").value<QObject*>());
+ QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
+ QMetaObject::invokeMethod(object, "releaseScarceResource");
+ QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, 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.
+ QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
+ delete object;
+
+ // 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->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.
+ srp_name = object->property("srp_name").toString();
+ expectedWarning = varComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
+ QMetaObject::invokeMethod(object, "retrieveScarceResource");
+ QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
+ eo = qobject_cast<ScarceResourceObject*>(QQmlProperty::read(object, "a").value<QObject*>());
+ QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
+ QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
+ delete object;
+
+ // test that if an Item which has JS ownership but has a scarce resource property is garbage collected,
+ // 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->property("varProperty").isValid()); // not assigned yet
+ QMetaObject::invokeMethod(object, "assignVarProperty");
+ QVERIFY(ep->scarceResources.isEmpty()); // the scarce resource is a VME property.
+ QMetaObject::invokeMethod(object, "deassignVarProperty");
+ QVERIFY(ep->scarceResources.isEmpty()); // should still be empty; the resource should have been released on gc.
+ delete object;
+
+ /* property variant semantics */
+
+ // test that scarce resources are handled properly in signal invocation
+ QQmlComponent variantComponentTen(&engine, testFileUrl("scarceResourceSignal.variant.qml"));
+ object = variantComponentTen.create();
+ QVERIFY(object != 0);
+ srsc = object->findChild<QObject*>("srsc");
+ QVERIFY(srsc);
+ QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
+ QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
+ eo = qobject_cast<ScarceResourceObject*>(QQmlProperty::read(object, "a").value<QObject*>());
+ QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
+ QMetaObject::invokeMethod(srsc, "testSignal");
+ QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
+ QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
+ eo = qobject_cast<ScarceResourceObject*>(QQmlProperty::read(object, "a").value<QObject*>());
+ QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
+ QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
+ QVERIFY(srsc->property("scarceResourceCopy").isValid());
+ QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
+ eo = qobject_cast<ScarceResourceObject*>(QQmlProperty::read(object, "a").value<QObject*>());
+ QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
+ QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
+ delete object;
+
+ // 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->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.
+ QMetaObject::invokeMethod(object, "retrieveScarceResource");
+ QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
+ QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
+ eo = qobject_cast<ScarceResourceObject*>(QQmlProperty::read(object, "a").value<QObject*>());
+ QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
+ QMetaObject::invokeMethod(object, "releaseScarceResource");
+ QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, 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.
+ QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
+ delete object;
+
+ // 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->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.
+ srp_name = object->property("srp_name").toString();
+ expectedWarning = variantComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
+ QMetaObject::invokeMethod(object, "retrieveScarceResource");
+ QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
+ eo = qobject_cast<ScarceResourceObject*>(QQmlProperty::read(object, "a").value<QObject*>());
+ QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
+ QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
+ delete object;
+}
+
+void tst_qqmlecmascript::scarceResources_data()
+{
+ QTest::addColumn<QUrl>("qmlFile");
+ QTest::addColumn<bool>("readDetachStatus");
+ QTest::addColumn<bool>("expectedDetachStatus");
+ QTest::addColumn<QStringList>("propertyNames");
+ QTest::addColumn<QVariantList>("expectedValidity");
+ QTest::addColumn<QVariantList>("expectedValues");
+ QTest::addColumn<QStringList>("expectedErrors");
+
+ QPixmap origPixmap(100, 100);
+ origPixmap.fill(Qt::blue);
+
+ /* property var semantics */
+
+ // in the following three cases, the instance created from the component
+ // has a property which is a copy of the scarce resource; hence, the
+ // resource should NOT be detached prior to deletion of the object instance,
+ // unless the resource is destroyed explicitly.
+ QTest::newRow("var: import scarce resource copy directly")
+ << testFileUrl("scarceResourceCopy.var.qml")
+ << true
+ << false // won't be detached, because assigned to property and not explicitly released
+ << (QStringList() << QLatin1String("scarceResourceCopy"))
+ << (QList<QVariant>() << true)
+ << (QList<QVariant>() << origPixmap)
+ << QStringList();
+
+ QTest::newRow("var: import scarce resource copy from JS")
+ << testFileUrl("scarceResourceCopyFromJs.var.qml")
+ << true
+ << false // won't be detached, because assigned to property and not explicitly released
+ << (QStringList() << QLatin1String("scarceResourceCopy"))
+ << (QList<QVariant>() << true)
+ << (QList<QVariant>() << origPixmap)
+ << QStringList();
+
+ QTest::newRow("var: import released scarce resource copy from JS")
+ << testFileUrl("scarceResourceDestroyedCopy.var.qml")
+ << true
+ << true // explicitly released, so it will be detached
+ << (QStringList() << QLatin1String("scarceResourceCopy"))
+ << (QList<QVariant>() << false)
+ << (QList<QVariant>() << QVariant())
+ << QStringList();
+
+ // in the following three cases, no other copy should exist in memory,
+ // and so it should be detached (unless explicitly preserved).
+ QTest::newRow("var: import auto-release SR from JS in binding side-effect")
+ << testFileUrl("scarceResourceTest.var.qml")
+ << true
+ << true // auto released, so it will be detached
+ << (QStringList() << QLatin1String("scarceResourceTest"))
+ << (QList<QVariant>() << true)
+ << (QList<QVariant>() << QVariant(100))
+ << QStringList();
+ QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
+ << testFileUrl("scarceResourceTestPreserve.var.qml")
+ << true
+ << false // won't be detached because we explicitly preserve it
+ << (QStringList() << QLatin1String("scarceResourceTest"))
+ << (QList<QVariant>() << true)
+ << (QList<QVariant>() << QVariant(100))
+ << QStringList();
+ QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
+ << testFileUrl("scarceResourceTestMultiple.var.qml")
+ << true
+ << true // will be detached because all resources were released manually or automatically.
+ << (QStringList() << QLatin1String("scarceResourceTest"))
+ << (QList<QVariant>() << true)
+ << (QList<QVariant>() << QVariant(100))
+ << QStringList();
+
+ // In the following three cases, test that scarce resources are handled
+ // correctly for imports.
+ QTest::newRow("var: import with no binding")
+ << testFileUrl("scarceResourceCopyImportNoBinding.var.qml")
+ << false // cannot check detach status.
+ << false
+ << QStringList()
+ << QList<QVariant>()
+ << QList<QVariant>()
+ << QStringList();
+ QTest::newRow("var: import with binding without explicit preserve")
+ << testFileUrl("scarceResourceCopyImportNoBinding.var.qml")
+ << false
+ << false
+ << (QStringList() << QLatin1String("scarceResourceCopy"))
+ << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
+ << (QList<QVariant>() << QVariant())
+ << QStringList();
+ QTest::newRow("var: import with explicit release after binding evaluation")
+ << testFileUrl("scarceResourceCopyImport.var.qml")
+ << false
+ << false
+ << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
+ << (QList<QVariant>() << false << false << false << true) // since property var = JS object reference, by releasing the provider's resource, all handles are invalidated.
+ << (QList<QVariant>() << QVariant() << QVariant() << QVariant() << QVariant(true))
+ << QStringList();
+ QTest::newRow("var: import with different js objects")
+ << testFileUrl("scarceResourceCopyImportDifferent.var.qml")
+ << false
+ << false
+ << (QStringList() << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
+ << (QList<QVariant>() << false << true << true) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
+ << (QList<QVariant>() << QVariant() << QVariant(origPixmap) << QVariant(false))
+ << QStringList();
+ QTest::newRow("var: import with different js objects and explicit release")
+ << testFileUrl("scarceResourceMultipleDifferentNoBinding.var.qml")
+ << false
+ << false
+ << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
+ << (QList<QVariant>() << true << false) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
+ << (QList<QVariant>() << QVariant(origPixmap) << QVariant())
+ << QStringList();
+ QTest::newRow("var: import with same js objects and explicit release")
+ << testFileUrl("scarceResourceMultipleSameNoBinding.var.qml")
+ << false
+ << false
+ << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
+ << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
+ << (QList<QVariant>() << QVariant() << QVariant())
+ << QStringList();
+ QTest::newRow("var: binding with same js objects and explicit release")
+ << testFileUrl("scarceResourceMultipleSameWithBinding.var.qml")
+ << false
+ << false
+ << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
+ << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
+ << (QList<QVariant>() << QVariant() << QVariant())
+ << QStringList();
+
+
+ /* property variant semantics */
+
+ // in the following three cases, the instance created from the component
+ // has a property which is a copy of the scarce resource; hence, the
+ // resource should NOT be detached prior to deletion of the object instance,
+ // unless the resource is destroyed explicitly.
+ QTest::newRow("variant: import scarce resource copy directly")
+ << testFileUrl("scarceResourceCopy.variant.qml")
+ << true
+ << false // won't be detached, because assigned to property and not explicitly released
+ << (QStringList() << QLatin1String("scarceResourceCopy"))
+ << (QList<QVariant>() << true)
+ << (QList<QVariant>() << origPixmap)
+ << QStringList();
+
+ QTest::newRow("variant: import scarce resource copy from JS")
+ << testFileUrl("scarceResourceCopyFromJs.variant.qml")
+ << true
+ << false // won't be detached, because assigned to property and not explicitly released
+ << (QStringList() << QLatin1String("scarceResourceCopy"))
+ << (QList<QVariant>() << true)
+ << (QList<QVariant>() << origPixmap)
+ << QStringList();
+
+ QTest::newRow("variant: import released scarce resource copy from JS")
+ << testFileUrl("scarceResourceDestroyedCopy.variant.qml")
+ << true
+ << true // explicitly released, so it will be detached
+ << (QStringList() << QLatin1String("scarceResourceCopy"))
+ << (QList<QVariant>() << false)
+ << (QList<QVariant>() << QVariant())
+ << QStringList();
+
+ // in the following three cases, no other copy should exist in memory,
+ // and so it should be detached (unless explicitly preserved).
+ QTest::newRow("variant: import auto-release SR from JS in binding side-effect")
+ << testFileUrl("scarceResourceTest.variant.qml")
+ << true
+ << true // auto released, so it will be detached
+ << (QStringList() << QLatin1String("scarceResourceTest"))
+ << (QList<QVariant>() << true)
+ << (QList<QVariant>() << QVariant(100))
+ << QStringList();
+ QTest::newRow("variant: import explicit-preserve SR from JS in binding side-effect")
+ << testFileUrl("scarceResourceTestPreserve.variant.qml")
+ << true
+ << false // won't be detached because we explicitly preserve it
+ << (QStringList() << QLatin1String("scarceResourceTest"))
+ << (QList<QVariant>() << true)
+ << (QList<QVariant>() << QVariant(100))
+ << QStringList();
+ QTest::newRow("variant: import multiple scarce resources")
+ << testFileUrl("scarceResourceTestMultiple.variant.qml")
+ << true
+ << true // will be detached because all resources were released manually or automatically.
+ << (QStringList() << QLatin1String("scarceResourceTest"))
+ << (QList<QVariant>() << true)
+ << (QList<QVariant>() << QVariant(100))
+ << QStringList();
+
+ // In the following three cases, test that scarce resources are handled
+ // correctly for imports.
+ QTest::newRow("variant: import with no binding")
+ << testFileUrl("scarceResourceCopyImportNoBinding.variant.qml")
+ << false // cannot check detach status.
+ << false
+ << QStringList()
+ << QList<QVariant>()
+ << QList<QVariant>()
+ << QStringList();
+ QTest::newRow("variant: import with binding without explicit preserve")
+ << testFileUrl("scarceResourceCopyImportNoBinding.variant.qml")
+ << false
+ << false
+ << (QStringList() << QLatin1String("scarceResourceCopy"))
+ << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
+ << (QList<QVariant>() << QVariant())
+ << QStringList();
+ QTest::newRow("variant: import with explicit release after binding evaluation")
+ << testFileUrl("scarceResourceCopyImport.variant.qml")
+ << false
+ << false
+ << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo"))
+ << (QList<QVariant>() << true << true << false) // since property variant = variant copy, releasing the provider's resource does not invalidate previously assigned copies.
+ << (QList<QVariant>() << origPixmap << origPixmap << QVariant())
+ << QStringList();
+}
+
+void tst_qqmlecmascript::scarceResources()
+{
+ QFETCH(QUrl, qmlFile);
+ QFETCH(bool, readDetachStatus);
+ QFETCH(bool, expectedDetachStatus);
+ QFETCH(QStringList, propertyNames);
+ QFETCH(QVariantList, expectedValidity);
+ QFETCH(QVariantList, expectedValues);
+ QFETCH(QStringList, expectedErrors);
+
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(&engine);
+ ScarceResourceObject *eo = 0;
+ QObject *object = 0;
+
+ QQmlComponent c(&engine, qmlFile);
+ object = c.create();
+ QVERIFY(object != 0);
+ for (int i = 0; i < propertyNames.size(); ++i) {
+ QString prop = propertyNames.at(i);
+ bool validity = expectedValidity.at(i).toBool();
+ QVariant value = expectedValues.at(i);
+
+ QCOMPARE(object->property(prop.toLatin1().constData()).isValid(), validity);
+ if (value.type() == QVariant::Int) {
+ QCOMPARE(object->property(prop.toLatin1().constData()).toInt(), value.toInt());
+ } else if (value.type() == QVariant::Pixmap) {
+ QCOMPARE(object->property(prop.toLatin1().constData()).value<QPixmap>(), value.value<QPixmap>());
+ }
+ }
+
+ if (readDetachStatus) {
+ eo = qobject_cast<ScarceResourceObject*>(QQmlProperty::read(object, "a").value<QObject*>());
+ QCOMPARE(eo->scarceResourceIsDetached(), expectedDetachStatus);
+ }
+
+ QVERIFY(ep->scarceResources.isEmpty());
+ delete object;
+}
+
+void tst_qqmlecmascript::propertyChangeSlots()
+{
+ // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
+ QQmlComponent component(&engine, testFileUrl("changeslots/propertyChangeSlots.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ delete object;
+
+ // ensure that invalid property names fail properly.
+ QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready");
+ QQmlComponent e1(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.1.qml"));
+ QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
+ QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
+ object = e1.create();
+ QVERIFY(object == 0);
+ delete object;
+
+ QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready");
+ QQmlComponent e2(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.2.qml"));
+ expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
+ QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
+ object = e2.create();
+ QVERIFY(object == 0);
+ delete object;
+
+ QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready");
+ QQmlComponent e3(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.3.qml"));
+ expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
+ QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
+ object = e3.create();
+ QVERIFY(object == 0);
+ delete object;
+
+ QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready");
+ QQmlComponent e4(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.4.qml"));
+ expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
+ QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
+ object = e4.create();
+ QVERIFY(object == 0);
+ delete object;
+}
+
+void tst_qqmlecmascript::propertyVar_data()
+{
+ QTest::addColumn<QUrl>("qmlFile");
+
+ // valid
+ QTest::newRow("non-bindable object subproperty changed") << testFileUrl("propertyVar.1.qml");
+ QTest::newRow("non-bindable object changed") << testFileUrl("propertyVar.2.qml");
+ QTest::newRow("primitive changed") << testFileUrl("propertyVar.3.qml");
+ QTest::newRow("javascript array modification") << testFileUrl("propertyVar.4.qml");
+ QTest::newRow("javascript map modification") << testFileUrl("propertyVar.5.qml");
+ QTest::newRow("javascript array assignment") << testFileUrl("propertyVar.6.qml");
+ QTest::newRow("javascript map assignment") << testFileUrl("propertyVar.7.qml");
+ QTest::newRow("literal property assignment") << testFileUrl("propertyVar.8.qml");
+ QTest::newRow("qobject property assignment") << testFileUrl("propertyVar.9.qml");
+ QTest::newRow("base class var property assignment") << testFileUrl("propertyVar.10.qml");
+}
+
+void tst_qqmlecmascript::propertyVar()
+{
+ QFETCH(QUrl, qmlFile);
+
+ QQmlComponent component(&engine, qmlFile);
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test").toBool(), true);
+
+ delete object;
+}
+
+// Tests that we can write QVariant values to var properties from C++
+void tst_qqmlecmascript::propertyVarCpp()
+{
+ QObject *object = 0;
+
+ // 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.
+ QQmlComponent component(&engine, testFileUrl("propertyVarCpp.qml"));
+ object = component.create();
+ QVERIFY(object != 0);
+ // assign int to property var that currently has int assigned
+ QVERIFY(object->setProperty("varProperty", QVariant::fromValue(10)));
+ QCOMPARE(object->property("varBound"), QVariant(15));
+ QCOMPARE(object->property("intBound"), QVariant(15));
+ QCOMPARE(object->property("varProperty").userType(), (int)QVariant::Int);
+ QCOMPARE(object->property("varBound").userType(), (int)QVariant::Int);
+ // assign string to property var that current has bool assigned
+ QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::Bool);
+ QVERIFY(object->setProperty("varProperty2", QVariant(QLatin1String("randomString"))));
+ QCOMPARE(object->property("varProperty2"), QVariant(QLatin1String("randomString")));
+ QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::String);
+ // now enforce behaviour when accessing JavaScript objects from cpp.
+ QCOMPARE(object->property("jsobject").userType(), (int)QVariant::Map);
+ delete object;
+}
+
+static void gc(QQmlEngine &engine)
+{
+ engine.collectGarbage();
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
+}
+
+void tst_qqmlecmascript::propertyVarOwnership()
+{
+ // Referenced JS objects are not collected
+ {
+ QQmlComponent component(&engine, testFileUrl("propertyVarOwnership.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ QCOMPARE(object->property("test").toBool(), false);
+ QMetaObject::invokeMethod(object, "runTest");
+ QCOMPARE(object->property("test").toBool(), true);
+ delete object;
+ }
+ // Referenced JS objects are not collected
+ {
+ QQmlComponent component(&engine, testFileUrl("propertyVarOwnership.2.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ QCOMPARE(object->property("test").toBool(), false);
+ QMetaObject::invokeMethod(object, "runTest");
+ QCOMPARE(object->property("test").toBool(), true);
+ delete object;
+ }
+ // Qt objects are not collected until they've been dereferenced
+ {
+ QQmlComponent component(&engine, testFileUrl("propertyVarOwnership.3.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test2").toBool(), false);
+ QCOMPARE(object->property("test2").toBool(), false);
+
+ QMetaObject::invokeMethod(object, "runTest");
+ QCOMPARE(object->property("test1").toBool(), true);
+
+ QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
+ QVERIFY(!referencedObject.isNull());
+ gc(engine);
+ QVERIFY(!referencedObject.isNull());
+
+ QMetaObject::invokeMethod(object, "runTest2");
+ QCOMPARE(object->property("test2").toBool(), true);
+ gc(engine);
+ QVERIFY(referencedObject.isNull());
+
+ delete object;
+ }
+ // Self reference does not prevent Qt object collection
+ {
+ QQmlComponent component(&engine, testFileUrl("propertyVarOwnership.4.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test").toBool(), true);
+
+ QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
+ QVERIFY(!referencedObject.isNull());
+ gc(engine);
+ QVERIFY(!referencedObject.isNull());
+
+ QMetaObject::invokeMethod(object, "runTest");
+ gc(engine);
+ QVERIFY(referencedObject.isNull());
+
+ delete object;
+ }
+}
+
+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.
+ QQmlComponent component(&engine, testFileUrl("propertyVarImplicitOwnership.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ QMetaObject::invokeMethod(object, "assignCircular");
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
+ QObject *rootObject = object->property("vp").value<QObject*>();
+ QVERIFY(rootObject != 0);
+ QObject *childObject = rootObject->findChild<QObject*>("text");
+ QVERIFY(childObject != 0);
+ QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
+ QCOMPARE(childObject->property("textCanary").toInt(), 10);
+ QMetaObject::invokeMethod(childObject, "constructQObject"); // creates a reference to a constructed QObject.
+ QWeakPointer<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::processEvents();
+ QVERIFY(!qobjectGuard.isNull());
+ QMetaObject::invokeMethod(object, "deassignCircular");
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
+ QVERIFY(qobjectGuard.isNull()); // should have been collected now.
+ delete object;
+}
+
+void tst_qqmlecmascript::propertyVarReparent()
+{
+ // ensure that nothing breaks if we re-parent objects
+ QQmlComponent component(&engine, testFileUrl("propertyVar.reparent.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ QMetaObject::invokeMethod(object, "assignVarProp");
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
+ QObject *rect = object->property("vp").value<QObject*>();
+ QObject *text = rect->findChild<QObject*>("textOne");
+ QObject *text2 = rect->findChild<QObject*>("textTwo");
+ QWeakPointer<QObject> rectGuard(rect);
+ QWeakPointer<QObject> textGuard(text);
+ QWeakPointer<QObject> text2Guard(text2);
+ QVERIFY(!rectGuard.isNull());
+ QVERIFY(!textGuard.isNull());
+ QVERIFY(!text2Guard.isNull());
+ QCOMPARE(text->property("textCanary").toInt(), 11);
+ QCOMPARE(text2->property("textCanary").toInt(), 12);
+ // now construct an image which we will reparent.
+ QMetaObject::invokeMethod(text2, "constructQObject");
+ QObject *image = text2->property("vp").value<QObject*>();
+ QWeakPointer<QObject> imageGuard(image);
+ QVERIFY(!imageGuard.isNull());
+ QCOMPARE(image->property("imageCanary").toInt(), 13);
+ // now reparent the "Image" object (currently, it has JS ownership)
+ image->setParent(text); // shouldn't be collected after deassignVp now, since has a parent.
+ QMetaObject::invokeMethod(text2, "deassignVp");
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
+ QCOMPARE(text->property("textCanary").toInt(), 11);
+ QCOMPARE(text2->property("textCanary").toInt(), 22);
+ QVERIFY(!imageGuard.isNull()); // should still be alive.
+ QCOMPARE(image->property("imageCanary").toInt(), 13); // still able to access var properties
+ QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
+ QVERIFY(imageGuard.isNull()); // should now have been deleted, due to parent being deleted.
+ delete object;
+}
+
+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.
+ QQmlComponent component(&engine, testFileUrl("propertyVar.reparent.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ QMetaObject::invokeMethod(object, "assignVarProp");
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
+ QObject *rect = object->property("vp").value<QObject*>();
+ QObject *text = rect->findChild<QObject*>("textOne");
+ QObject *text2 = rect->findChild<QObject*>("textTwo");
+ QWeakPointer<QObject> rectGuard(rect);
+ QWeakPointer<QObject> textGuard(text);
+ QWeakPointer<QObject> text2Guard(text2);
+ QVERIFY(!rectGuard.isNull());
+ QVERIFY(!textGuard.isNull());
+ QVERIFY(!text2Guard.isNull());
+ QCOMPARE(text->property("textCanary").toInt(), 11);
+ QCOMPARE(text2->property("textCanary").toInt(), 12);
+ // now construct an image which we will reparent.
+ QMetaObject::invokeMethod(text2, "constructQObject");
+ QObject *image = text2->property("vp").value<QObject*>();
+ QWeakPointer<QObject> imageGuard(image);
+ QVERIFY(!imageGuard.isNull());
+ QCOMPARE(image->property("imageCanary").toInt(), 13);
+ // now reparent the "Image" object (currently, it has JS ownership)
+ image->setParent(object); // reparented to base object. after deassignVarProp, the ctxt will be invalid.
+ QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
+ QVERIFY(!imageGuard.isNull()); // should still be alive.
+ QVERIFY(!image->property("imageCanary").isValid()); // but varProperties won't be available (null context).
+ delete object;
+ QVERIFY(imageGuard.isNull()); // should now be dead.
+}
+
+void tst_qqmlecmascript::propertyVarCircular()
+{
+ // enforce behaviour regarding circular references - ensure qdvmemo deletion.
+ QQmlComponent component(&engine, testFileUrl("propertyVar.circular.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
+ QCOMPARE(object->property("canaryInt"), QVariant(5));
+ QVariant canaryResourceVariant = object->property("canaryResource");
+ QVERIFY(canaryResourceVariant.isValid());
+ QPixmap canaryResourcePixmap = canaryResourceVariant.value<QPixmap>();
+ canaryResourceVariant = QVariant(); // invalidate it to remove one copy of the pixmap from memory.
+ QMetaObject::invokeMethod(object, "deassignCanaryResource"); // remove one copy of the pixmap from memory
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
+ QVERIFY(!canaryResourcePixmap.isDetached()); // two copies extant - this and the propertyVar.vp.vp.vp.vp.memoryHog.
+ QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
+ QCOMPARE(object->property("canaryInt"), QVariant(2));
+ QCOMPARE(object->property("canaryResource"), QVariant(1));
+ QVERIFY(canaryResourcePixmap.isDetached()); // now detached, since orig copy was member of qdvmemo which was deleted.
+ delete object;
+}
+
+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.
+ QQmlComponent component(&engine, testFileUrl("propertyVar.circular.2.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ QMetaObject::invokeMethod(object, "assignCircular");
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
+ QObject *rootObject = object->property("vp").value<QObject*>();
+ QVERIFY(rootObject != 0);
+ QObject *childObject = rootObject->findChild<QObject*>("text");
+ QVERIFY(childObject != 0);
+ QWeakPointer<QObject> rootObjectTracker(rootObject);
+ QVERIFY(!rootObjectTracker.isNull());
+ QWeakPointer<QObject> childObjectTracker(childObject);
+ QVERIFY(!childObjectTracker.isNull());
+ gc(engine);
+ QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
+ QCOMPARE(childObject->property("textCanary").toInt(), 10);
+ QMetaObject::invokeMethod(object, "deassignCircular");
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
+ QVERIFY(rootObjectTracker.isNull()); // should have been collected
+ QVERIFY(childObjectTracker.isNull()); // should have been collected
+ delete object;
+}
+
+void tst_qqmlecmascript::propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter)
+{
+ *(int*)(parameter) += 1;
+ qPersistentDispose(object);
+}
+
+void tst_qqmlecmascript::propertyVarInheritance()
+{
+ int propertyVarWeakRefCallbackCount = 0;
+
+ // enforce behaviour regarding element inheritance - ensure handle disposal.
+ // The particular component under test here has a chain of references.
+ QQmlComponent component(&engine, testFileUrl("propertyVar.inherit.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
+ QCoreApplication::sendPostedEvents(0, 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*>();
+ QObject *ico5 = object->property("varProperty").value<QObject*>()->property("inheritanceVarProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
+ QQmlVMEMetaObject *icovmemo = ((QQmlVMEMetaObject *)(ico5->metaObject()));
+ QQmlVMEMetaObject *ccovmemo = ((QQmlVMEMetaObject *)(cco5->metaObject()));
+ v8::Persistent<v8::Value> icoCanaryHandle;
+ v8::Persistent<v8::Value> ccoCanaryHandle;
+ {
+ v8::HandleScope hs;
+ // 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.
+ icoCanaryHandle = qPersistentNew(icovmemo->vmeProperty(ico5->metaObject()->indexOfProperty("circ")));
+ ccoCanaryHandle = qPersistentNew(ccovmemo->vmeProperty(cco5->metaObject()->indexOfProperty("circ")));
+ // we make them weak and invoke the gc, but we should not hit the weak-callback yet
+ // as the varproperties array of each vmemo still references the resource.
+ icoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
+ ccoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
+ gc(engine);
+ QVERIFY(propertyVarWeakRefCallbackCount == 0);
+ }
+ // now we deassign the var prop, which should trigger collection of item subtrees.
+ QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
+ // ensure that there are only weak handles to the underlying varProperties array remaining.
+ gc(engine);
+ QCOMPARE(propertyVarWeakRefCallbackCount, 2); // should have been called for both, since all refs should be weak.
+ delete object;
+ // since there are no parent vmemo's to keep implicit references alive, and the only handles
+ // to what remains are weak, all varProperties arrays must have been collected.
+}
+
+void tst_qqmlecmascript::propertyVarInheritance2()
+{
+ int propertyVarWeakRefCallbackCount = 0;
+
+ // 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.
+ QQmlComponent component(&engine, testFileUrl("propertyVar.circular.2.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ QMetaObject::invokeMethod(object, "assignCircular");
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
+ QObject *rootObject = object->property("vp").value<QObject*>();
+ QVERIFY(rootObject != 0);
+ QObject *childObject = rootObject->findChild<QObject*>("text");
+ QVERIFY(childObject != 0);
+ QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
+ QCOMPARE(childObject->property("textCanary").toInt(), 10);
+ v8::Persistent<v8::Value> childObjectVarArrayValueHandle;
+ {
+ v8::HandleScope hs;
+ propertyVarWeakRefCallbackCount = 0; // reset callback count.
+ childObjectVarArrayValueHandle = qPersistentNew(((QQmlVMEMetaObject *)(childObject->metaObject()))->vmeProperty(childObject->metaObject()->indexOfProperty("vp")));
+ childObjectVarArrayValueHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
+ gc(engine);
+ QVERIFY(propertyVarWeakRefCallbackCount == 0); // should not have been collected yet.
+ QCOMPARE(childObject->property("vp").value<QObject*>(), rootObject);
+ QCOMPARE(childObject->property("textCanary").toInt(), 10);
+ }
+ QMetaObject::invokeMethod(object, "deassignCircular");
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
+ QVERIFY(propertyVarWeakRefCallbackCount == 1); // should have been collected now.
+ delete object;
+}
+
+// Ensure that QObject type conversion works on binding assignment
+void tst_qqmlecmascript::elementAssign()
+{
+ QQmlComponent component(&engine, testFileUrl("elementAssign.qml"));
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test").toBool(), true);
+
+ delete object;
+}
+
+// QTBUG-12457
+void tst_qqmlecmascript::objectPassThroughSignals()
+{
+ QQmlComponent component(&engine, testFileUrl("objectsPassThroughSignals.qml"));
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test").toBool(), true);
+
+ delete object;
+}
+
+// QTBUG-21626
+void tst_qqmlecmascript::objectConversion()
+{
+ QQmlComponent component(&engine, testFileUrl("objectConversion.qml"));
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ QVariant retn;
+ QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn));
+ QCOMPARE(retn.value<QVariantMap>().value("test"), QVariant(100));
+
+ delete object;
+}
+
+
+// QTBUG-20242
+void tst_qqmlecmascript::booleanConversion()
+{
+ QQmlComponent component(&engine, testFileUrl("booleanConversion.qml"));
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test_true1").toBool(), true);
+ QCOMPARE(object->property("test_true2").toBool(), true);
+ QCOMPARE(object->property("test_true3").toBool(), true);
+ QCOMPARE(object->property("test_true4").toBool(), true);
+ QCOMPARE(object->property("test_true5").toBool(), true);
+
+ QCOMPARE(object->property("test_false1").toBool(), false);
+ QCOMPARE(object->property("test_false2").toBool(), false);
+ QCOMPARE(object->property("test_false3").toBool(), false);
+
+ delete object;
+}
+
+void tst_qqmlecmascript::handleReferenceManagement()
+{
+
+ int dtorCount = 0;
+ {
+ // Linear QObject reference
+ QQmlEngine hrmEngine;
+ QQmlComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.object.1.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
+ cro->setEngine(&hrmEngine);
+ cro->setDtorCount(&dtorCount);
+ QMetaObject::invokeMethod(object, "createReference");
+ gc(engine);
+ QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
+ delete object;
+ hrmEngine.collectGarbage();
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
+ QCOMPARE(dtorCount, 3);
+ }
+
+ dtorCount = 0;
+ {
+ // Circular QObject reference
+ QQmlEngine hrmEngine;
+ QQmlComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.object.2.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
+ cro->setEngine(&hrmEngine);
+ cro->setDtorCount(&dtorCount);
+ QMetaObject::invokeMethod(object, "circularReference");
+ gc(engine);
+ 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::processEvents();
+ QCOMPARE(dtorCount, 3);
+ }
+
+ dtorCount = 0;
+ {
+ // Linear handle reference
+ QQmlEngine hrmEngine;
+ QQmlComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.handle.1.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
+ QVERIFY(crh != 0);
+ crh->setEngine(&hrmEngine);
+ crh->setDtorCount(&dtorCount);
+ QMetaObject::invokeMethod(object, "createReference");
+ CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
+ CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
+ QVERIFY(first != 0);
+ QVERIFY(second != 0);
+ first->addReference(QQmlData::get(second)->v8object); // create reference
+ // now we have to reparent second and make second owned by JS.
+ second->setParent(0);
+ QQmlEngine::setObjectOwnership(second, QQmlEngine::JavaScriptOwnership);
+ gc(engine);
+ QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
+ delete object;
+ hrmEngine.collectGarbage();
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
+ QCOMPARE(dtorCount, 3);
+ }
+
+ dtorCount = 0;
+ {
+ // Circular handle reference
+ QQmlEngine hrmEngine;
+ QQmlComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.handle.2.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
+ QVERIFY(crh != 0);
+ crh->setEngine(&hrmEngine);
+ crh->setDtorCount(&dtorCount);
+ QMetaObject::invokeMethod(object, "circularReference");
+ CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
+ CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
+ QVERIFY(first != 0);
+ QVERIFY(second != 0);
+ first->addReference(QQmlData::get(second)->v8object); // create circular reference
+ second->addReference(QQmlData::get(first)->v8object); // note: must be weak.
+ // now we have to reparent and change ownership.
+ first->setParent(0);
+ second->setParent(0);
+ QQmlEngine::setObjectOwnership(first, QQmlEngine::JavaScriptOwnership);
+ QQmlEngine::setObjectOwnership(second, QQmlEngine::JavaScriptOwnership);
+ gc(engine);
+ QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
+ delete object;
+ hrmEngine.collectGarbage();
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
+ QCOMPARE(dtorCount, 3);
+ }
+
+ dtorCount = 0;
+ {
+ // multiple engine interaction - linear reference
+ QQmlEngine hrmEngine1;
+ QQmlEngine hrmEngine2;
+ QQmlComponent component1(&hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
+ QQmlComponent component2(&hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
+ QObject *object1 = component1.create();
+ QObject *object2 = component2.create();
+ QVERIFY(object1 != 0);
+ QVERIFY(object2 != 0);
+ CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
+ CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
+ QVERIFY(crh1 != 0);
+ QVERIFY(crh2 != 0);
+ crh1->setEngine(&hrmEngine1);
+ crh2->setEngine(&hrmEngine2);
+ crh1->setDtorCount(&dtorCount);
+ crh2->setDtorCount(&dtorCount);
+ QMetaObject::invokeMethod(object1, "createReference");
+ QMetaObject::invokeMethod(object2, "createReference");
+ CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
+ CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
+ CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
+ CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
+ QVERIFY(first1 != 0);
+ QVERIFY(second1 != 0);
+ QVERIFY(first2 != 0);
+ QVERIFY(second2 != 0);
+ first1->addReference(QQmlData::get(second2)->v8object); // create reference across engines
+ // now we have to reparent second2 and make second2 owned by JS.
+ second2->setParent(0);
+ QQmlEngine::setObjectOwnership(second2, QQmlEngine::JavaScriptOwnership);
+ gc(engine);
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
+ QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
+ delete object1;
+ delete object2;
+ hrmEngine1.collectGarbage();
+ hrmEngine2.collectGarbage();
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
+ QCOMPARE(dtorCount, 6);
+ }
+
+ dtorCount = 0;
+ {
+ // multiple engine interaction - circular reference
+ QQmlEngine hrmEngine1;
+ QQmlEngine hrmEngine2;
+ QQmlComponent component1(&hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
+ QQmlComponent component2(&hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
+ QObject *object1 = component1.create();
+ QObject *object2 = component2.create();
+ QVERIFY(object1 != 0);
+ QVERIFY(object2 != 0);
+ CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
+ CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
+ QVERIFY(crh1 != 0);
+ QVERIFY(crh2 != 0);
+ crh1->setEngine(&hrmEngine1);
+ crh2->setEngine(&hrmEngine2);
+ crh1->setDtorCount(&dtorCount);
+ crh2->setDtorCount(&dtorCount);
+ QMetaObject::invokeMethod(object1, "createReference");
+ QMetaObject::invokeMethod(object2, "createReference");
+ CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
+ CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
+ CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
+ CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
+ QVERIFY(first1 != 0);
+ QVERIFY(second1 != 0);
+ QVERIFY(first2 != 0);
+ QVERIFY(second2 != 0);
+ first1->addReference(QQmlData::get(second1)->v8object); // create linear reference within engine1
+ second1->addReference(QQmlData::get(second2)->v8object); // create linear reference across engines
+ second2->addReference(QQmlData::get(first2)->v8object); // create linear reference within engine2
+ first2->addReference(QQmlData::get(first1)->v8object); // close the loop - circular ref across engines
+ // now we have to reparent and change ownership to JS.
+ first1->setParent(0);
+ second1->setParent(0);
+ first2->setParent(0);
+ second2->setParent(0);
+ QQmlEngine::setObjectOwnership(first1, QQmlEngine::JavaScriptOwnership);
+ QQmlEngine::setObjectOwnership(second1, QQmlEngine::JavaScriptOwnership);
+ QQmlEngine::setObjectOwnership(first2, QQmlEngine::JavaScriptOwnership);
+ QQmlEngine::setObjectOwnership(second2, QQmlEngine::JavaScriptOwnership);
+ gc(engine);
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
+ QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
+ delete object1;
+ delete object2;
+ hrmEngine1.collectGarbage();
+ hrmEngine2.collectGarbage();
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
+ QCOMPARE(dtorCount, 6);
+ }
+
+ dtorCount = 0;
+ {
+ // multiple engine interaction - linear reference with engine deletion
+ QQmlEngine *hrmEngine1 = new QQmlEngine;
+ QQmlEngine *hrmEngine2 = new QQmlEngine;
+ QQmlComponent component1(hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
+ QQmlComponent component2(hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
+ QObject *object1 = component1.create();
+ QObject *object2 = component2.create();
+ QVERIFY(object1 != 0);
+ QVERIFY(object2 != 0);
+ CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
+ CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
+ QVERIFY(crh1 != 0);
+ QVERIFY(crh2 != 0);
+ crh1->setEngine(hrmEngine1);
+ crh2->setEngine(hrmEngine2);
+ crh1->setDtorCount(&dtorCount);
+ crh2->setDtorCount(&dtorCount);
+ QMetaObject::invokeMethod(object1, "createReference");
+ QMetaObject::invokeMethod(object2, "createReference");
+ CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
+ CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
+ CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
+ CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
+ QVERIFY(first1 != 0);
+ QVERIFY(second1 != 0);
+ QVERIFY(first2 != 0);
+ QVERIFY(second2 != 0);
+ first1->addReference(QQmlData::get(second1)->v8object); // create linear reference within engine1
+ second1->addReference(QQmlData::get(second2)->v8object); // create linear reference across engines
+ second2->addReference(QQmlData::get(first2)->v8object); // create linear reference within engine2
+ // now we have to reparent and change ownership to JS.
+ first1->setParent(crh1);
+ second1->setParent(0);
+ first2->setParent(0);
+ second2->setParent(0);
+ QQmlEngine::setObjectOwnership(second1, QQmlEngine::JavaScriptOwnership);
+ QQmlEngine::setObjectOwnership(first2, QQmlEngine::JavaScriptOwnership);
+ QQmlEngine::setObjectOwnership(second2, QQmlEngine::JavaScriptOwnership);
+ gc(engine);
+ QCOMPARE(dtorCount, 0);
+ delete hrmEngine2;
+ gc(engine);
+ QCOMPARE(dtorCount, 0);
+ delete object1;
+ delete object2;
+ hrmEngine1->collectGarbage();
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
+ QCOMPARE(dtorCount, 6);
+ delete hrmEngine1;
+ }
+}
+
+void tst_qqmlecmascript::stringArg()
+{
+ QQmlComponent component(&engine, testFileUrl("stringArg.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ QMetaObject::invokeMethod(object, "success");
+ QVERIFY(object->property("returnValue").toBool());
+
+ QString w1 = testFileUrl("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
+ QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
+ QMetaObject::invokeMethod(object, "failure");
+ QVERIFY(object->property("returnValue").toBool());
+
+ delete object;
+}
+
+void tst_qqmlecmascript::readonlyDeclaration()
+{
+ QQmlComponent component(&engine, testFileUrl("readonlyDeclaration.qml"));
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test").toBool(), true);
+
+ delete object;
+}
+
+Q_DECLARE_METATYPE(QList<int>)
+Q_DECLARE_METATYPE(QList<qreal>)
+Q_DECLARE_METATYPE(QList<bool>)
+Q_DECLARE_METATYPE(QList<QString>)
+Q_DECLARE_METATYPE(QList<QUrl>)
+void tst_qqmlecmascript::sequenceConversionRead()
+{
+ {
+ QUrl qmlFile = testFileUrl("sequenceConversion.read.qml");
+ QQmlComponent component(&engine, qmlFile);
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
+ QVERIFY(seq != 0);
+
+ QMetaObject::invokeMethod(object, "readSequences");
+ QList<int> intList; intList << 1 << 2 << 3 << 4;
+ QCOMPARE(object->property("intListLength").toInt(), intList.length());
+ QCOMPARE(object->property("intList").value<QList<int> >(), intList);
+ QList<qreal> qrealList; qrealList << 1.1 << 2.2 << 3.3 << 4.4;
+ QCOMPARE(object->property("qrealListLength").toInt(), qrealList.length());
+ QCOMPARE(object->property("qrealList").value<QList<qreal> >(), qrealList);
+ QList<bool> boolList; boolList << true << false << true << false;
+ QCOMPARE(object->property("boolListLength").toInt(), boolList.length());
+ QCOMPARE(object->property("boolList").value<QList<bool> >(), boolList);
+ QList<QString> stringList; stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
+ QCOMPARE(object->property("stringListLength").toInt(), stringList.length());
+ QCOMPARE(object->property("stringList").value<QList<QString> >(), stringList);
+ QList<QUrl> urlList; urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com");
+ QCOMPARE(object->property("urlListLength").toInt(), urlList.length());
+ QCOMPARE(object->property("urlList").value<QList<QUrl> >(), urlList);
+ QStringList qstringList; qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
+ QCOMPARE(object->property("qstringListLength").toInt(), qstringList.length());
+ QCOMPARE(object->property("qstringList").value<QStringList>(), qstringList);
+
+ QMetaObject::invokeMethod(object, "readSequenceElements");
+ QCOMPARE(object->property("intVal").toInt(), 2);
+ QCOMPARE(object->property("qrealVal").toReal(), 2.2);
+ QCOMPARE(object->property("boolVal").toBool(), false);
+ QCOMPARE(object->property("stringVal").toString(), QString(QLatin1String("second")));
+ QCOMPARE(object->property("urlVal").toUrl(), QUrl("http://www.example2.com"));
+ QCOMPARE(object->property("qstringVal").toString(), QString(QLatin1String("second")));
+
+ QMetaObject::invokeMethod(object, "enumerateSequenceElements");
+ QCOMPARE(object->property("enumerationMatches").toBool(), true);
+
+ intList.clear(); intList << 1 << 2 << 3 << 4 << 5; // set by the enumerateSequenceElements test.
+ QQmlProperty seqProp(seq, "intListProperty");
+ QCOMPARE(seqProp.read().value<QList<int> >(), intList);
+ QQmlProperty seqProp2(seq, "intListProperty", &engine);
+ QCOMPARE(seqProp2.read().value<QList<int> >(), intList);
+
+ QMetaObject::invokeMethod(object, "testReferenceDeletion");
+ QCOMPARE(object->property("referenceDeletion").toBool(), true);
+
+ delete object;
+ }
+
+ {
+ QUrl qmlFile = testFileUrl("sequenceConversion.read.error.qml");
+ QQmlComponent component(&engine, qmlFile);
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
+ QVERIFY(seq != 0);
+
+ // we haven't registered QList<QPoint> as a sequence type.
+ QString warningOne = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
+ QString warningTwo = qmlFile.toString() + QLatin1String(":18: TypeError: Cannot read property 'length' of undefined");
+ QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
+ QTest::ignoreMessage(QtWarningMsg, warningTwo.toAscii().constData());
+
+ QMetaObject::invokeMethod(object, "performTest");
+
+ // QList<QPoint> has not been registered as a sequence type.
+ QCOMPARE(object->property("pointListLength").toInt(), 0);
+ QVERIFY(!object->property("pointList").isValid());
+ QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
+ QQmlProperty seqProp(seq, "pointListProperty", &engine);
+ QVERIFY(!seqProp.read().isValid()); // not a valid/known sequence type
+
+ delete object;
+ }
+}
+
+void tst_qqmlecmascript::sequenceConversionWrite()
+{
+ {
+ QUrl qmlFile = testFileUrl("sequenceConversion.write.qml");
+ QQmlComponent component(&engine, qmlFile);
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
+ QVERIFY(seq != 0);
+
+ QMetaObject::invokeMethod(object, "writeSequences");
+ QCOMPARE(object->property("success").toBool(), true);
+
+ QMetaObject::invokeMethod(object, "writeSequenceElements");
+ QCOMPARE(object->property("success").toBool(), true);
+
+ QMetaObject::invokeMethod(object, "writeOtherElements");
+ QCOMPARE(object->property("success").toBool(), true);
+
+ QMetaObject::invokeMethod(object, "testReferenceDeletion");
+ QCOMPARE(object->property("referenceDeletion").toBool(), true);
+
+ delete object;
+ }
+
+ {
+ QUrl qmlFile = testFileUrl("sequenceConversion.write.error.qml");
+ QQmlComponent component(&engine, qmlFile);
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
+ QVERIFY(seq != 0);
+
+ // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work.
+ QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to void");
+ QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
+
+ QMetaObject::invokeMethod(object, "performTest");
+
+ QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed
+ QCOMPARE(seq->pointListProperty(), pointList);
+
+ delete object;
+ }
+}
+
+void tst_qqmlecmascript::sequenceConversionArray()
+{
+ // ensure that in JS the returned sequences act just like normal JS Arrays.
+ QUrl qmlFile = testFileUrl("sequenceConversion.array.qml");
+ QQmlComponent component(&engine, qmlFile);
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ QMetaObject::invokeMethod(object, "indexedAccess");
+ QVERIFY(object->property("success").toBool());
+ QMetaObject::invokeMethod(object, "arrayOperations");
+ QVERIFY(object->property("success").toBool());
+ QMetaObject::invokeMethod(object, "testEqualitySemantics");
+ QVERIFY(object->property("success").toBool());
+ QMetaObject::invokeMethod(object, "testReferenceDeletion");
+ QCOMPARE(object->property("referenceDeletion").toBool(), true);
+ delete object;
+}
+
+
+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");
+ QQmlComponent component(&engine, qmlFile);
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ 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");
+ QString w4 = qmlFile.toString() + QLatin1String(":78: std::bad_alloc during length set");
+ QString w5 = qmlFile.toString() + QLatin1String(":83: std::bad_alloc during indexed set");
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(w1));
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(w2));
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(w3));
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(w4));
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(w5));
+ QMetaObject::invokeMethod(object, "indexedAccess");
+ QVERIFY(object->property("success").toBool());
+ delete object;
+}
+
+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");
+ QQmlComponent component(&engine, qmlFile);
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QMetaObject::invokeMethod(object, "testIntSequence");
+ QTRY_VERIFY(object->property("finished").toBool());
+ QVERIFY(object->property("success").toBool());
+
+ QMetaObject::invokeMethod(object, "testQrealSequence");
+ QTRY_VERIFY(object->property("finished").toBool());
+ QVERIFY(object->property("success").toBool());
+
+ QMetaObject::invokeMethod(object, "testBoolSequence");
+ QTRY_VERIFY(object->property("finished").toBool());
+ QVERIFY(object->property("success").toBool());
+
+ QMetaObject::invokeMethod(object, "testStringSequence");
+ QTRY_VERIFY(object->property("finished").toBool());
+ QVERIFY(object->property("success").toBool());
+
+ QMetaObject::invokeMethod(object, "testQStringSequence");
+ QTRY_VERIFY(object->property("finished").toBool());
+ QVERIFY(object->property("success").toBool());
+
+ QMetaObject::invokeMethod(object, "testUrlSequence");
+ QTRY_VERIFY(object->property("finished").toBool());
+ QVERIFY(object->property("success").toBool());
+
+ QMetaObject::invokeMethod(object, "testVariantSequence");
+ QTRY_VERIFY(object->property("finished").toBool());
+ QVERIFY(object->property("success").toBool());
+
+ delete object;
+}
+
+void tst_qqmlecmascript::sequenceConversionBindings()
+{
+ {
+ QUrl qmlFile = testFileUrl("sequenceConversion.bindings.qml");
+ QQmlComponent component(&engine, qmlFile);
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ 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));
+ QList<int> intListTwo; intListTwo << 1 << 2 << 3 << 12 << 14;
+ QCOMPARE(object->property("boundSequenceTwo").value<QList<int> >(), intListTwo);
+ delete object;
+ }
+
+ {
+ QUrl qmlFile = testFileUrl("sequenceConversion.bindings.error.qml");
+ QString warning = QString(QLatin1String("%1:17: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
+ QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
+ QQmlComponent component(&engine, qmlFile);
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ delete object;
+ }
+}
+
+void tst_qqmlecmascript::sequenceConversionCopy()
+{
+ QUrl qmlFile = testFileUrl("sequenceConversion.copy.qml");
+ QQmlComponent component(&engine, qmlFile);
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ QMetaObject::invokeMethod(object, "testCopySequences");
+ QCOMPARE(object->property("success").toBool(), true);
+ QMetaObject::invokeMethod(object, "readSequenceCopyElements");
+ QCOMPARE(object->property("success").toBool(), true);
+ QMetaObject::invokeMethod(object, "testEqualitySemantics");
+ QCOMPARE(object->property("success").toBool(), true);
+ delete object;
+}
+
+void tst_qqmlecmascript::assignSequenceTypes()
+{
+ // test binding array to sequence type property
+ {
+ QQmlComponent component(&engine, testFileUrl("assignSequenceTypes.1.qml"));
+ MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
+ QVERIFY(object != 0);
+ QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
+ QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
+ QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
+ QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
+ QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
+ QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
+ delete object;
+ }
+
+ // test binding literal to sequence type property
+ {
+ QQmlComponent component(&engine, testFileUrl("assignSequenceTypes.2.qml"));
+ MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
+ QVERIFY(object != 0);
+ QCOMPARE(object->intListProperty(), (QList<int>() << 1));
+ QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
+ QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
+ QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
+ QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
+ QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
+ delete object;
+ }
+
+ // test binding single value to sequence type property
+ {
+ QQmlComponent component(&engine, testFileUrl("assignSequenceTypes.3.qml"));
+ MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
+ QVERIFY(object != 0);
+ QCOMPARE(object->intListProperty(), (QList<int>() << 1));
+ QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
+ QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
+ QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
+ delete object;
+ }
+
+ // test assigning array to sequence type property in js function
+ {
+ QQmlComponent component(&engine, testFileUrl("assignSequenceTypes.4.qml"));
+ MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
+ QVERIFY(object != 0);
+ QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
+ QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
+ QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
+ QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
+ QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
+ QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
+ delete object;
+ }
+
+ // test assigning literal to sequence type property in js function
+ {
+ QQmlComponent component(&engine, testFileUrl("assignSequenceTypes.5.qml"));
+ MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
+ QVERIFY(object != 0);
+ QCOMPARE(object->intListProperty(), (QList<int>() << 1));
+ QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
+ QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
+ QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
+ QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
+ QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
+ delete object;
+ }
+
+ // test assigning single value to sequence type property in js function
+ {
+ QQmlComponent component(&engine, testFileUrl("assignSequenceTypes.6.qml"));
+ MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
+ QVERIFY(object != 0);
+ QCOMPARE(object->intListProperty(), (QList<int>() << 1));
+ QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
+ QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
+ QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
+ delete object;
+ }
+
+ // test QList<QUrl> literal assignment and binding assignment causes url resolution when required
+ {
+ QQmlComponent component(&engine, testFileUrl("assignSequenceTypes.7.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ 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);
+ 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"))));
+ QCOMPARE(msco4->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
+ QCOMPARE(msco5->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
+ delete object;
+ }
+}
+
+// Test that assigning a null object works
+// Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
+void tst_qqmlecmascript::nullObjectBinding()
+{
+ QQmlComponent component(&engine, testFileUrl("nullObjectBinding.qml"));
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
+
+ delete object;
+}
+
+// Test that bindings don't evaluate once the engine has been destroyed
+void tst_qqmlecmascript::deletedEngine()
+{
+ QQmlEngine *engine = new QQmlEngine;
+ QQmlComponent component(engine, testFileUrl("deletedEngine.qml"));
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("a").toInt(), 39);
+ object->setProperty("b", QVariant(9));
+ QCOMPARE(object->property("a").toInt(), 117);
+
+ delete engine;
+
+ QCOMPARE(object->property("a").toInt(), 117);
+ object->setProperty("b", QVariant(10));
+ QCOMPARE(object->property("a").toInt(), 117);
+
+ delete object;
+}
+
+// Test the crashing part of QTBUG-9705
+void tst_qqmlecmascript::libraryScriptAssert()
+{
+ QQmlComponent component(&engine, testFileUrl("libraryScriptAssert.qml"));
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ delete object;
+}
+
+void tst_qqmlecmascript::variantsAssignedUndefined()
+{
+ QQmlComponent component(&engine, testFileUrl("variantsAssignedUndefined.qml"));
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test1").toInt(), 10);
+ QCOMPARE(object->property("test2").toInt(), 11);
+
+ object->setProperty("runTest", true);
+
+ QCOMPARE(object->property("test1"), QVariant());
+ QCOMPARE(object->property("test2"), QVariant());
+
+
+ delete object;
+}
+
+void tst_qqmlecmascript::qtbug_9792()
+{
+ QQmlComponent component(&engine, testFileUrl("qtbug_9792.qml"));
+
+ QQmlContext *context = new QQmlContext(engine.rootContext());
+
+ MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
+ QVERIFY(object != 0);
+
+ QTest::ignoreMessage(QtDebugMsg, "Hello world!");
+ object->basicSignal();
+
+ delete context;
+
+ transientErrorsMsgCount = 0;
+ QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
+
+ object->basicSignal();
+
+ qInstallMsgHandler(old);
+
+ QCOMPARE(transientErrorsMsgCount, 0);
+
+ delete object;
+}
+
+// Verifies that QQmlGuard<>s used in the vmemetaobject are cleaned correctly
+void tst_qqmlecmascript::qtcreatorbug_1289()
+{
+ QQmlComponent component(&engine, testFileUrl("qtcreatorbug_1289.qml"));
+
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ QObject *nested = qvariant_cast<QObject *>(o->property("object"));
+ QVERIFY(nested != 0);
+
+ QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
+
+ delete nested;
+ nested = qvariant_cast<QObject *>(o->property("object"));
+ QVERIFY(nested == 0);
+
+ // If the bug is present, the next line will crash
+ delete o;
+}
+
+// Test that we shut down without stupid warnings
+void tst_qqmlecmascript::noSpuriousWarningsAtShutdown()
+{
+ {
+ QQmlComponent component(&engine, testFileUrl("noSpuriousWarningsAtShutdown.qml"));
+
+ QObject *o = component.create();
+
+ transientErrorsMsgCount = 0;
+ QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
+
+ delete o;
+
+ qInstallMsgHandler(old);
+
+ QCOMPARE(transientErrorsMsgCount, 0);
+ }
+
+
+ {
+ QQmlComponent component(&engine, testFileUrl("noSpuriousWarningsAtShutdown.2.qml"));
+
+ QObject *o = component.create();
+
+ transientErrorsMsgCount = 0;
+ QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
+
+ delete o;
+
+ qInstallMsgHandler(old);
+
+ QCOMPARE(transientErrorsMsgCount, 0);
+ }
+}
+
+void tst_qqmlecmascript::canAssignNullToQObject()
+{
+ {
+ QQmlComponent component(&engine, testFileUrl("canAssignNullToQObject.1.qml"));
+
+ MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(o != 0);
+
+ QVERIFY(o->objectProperty() != 0);
+
+ o->setProperty("runTest", true);
+
+ QVERIFY(o->objectProperty() == 0);
+
+ delete o;
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("canAssignNullToQObject.2.qml"));
+
+ MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(o != 0);
+
+ QVERIFY(o->objectProperty() == 0);
+
+ delete o;
+ }
+}
+
+void tst_qqmlecmascript::functionAssignment_fromBinding()
+{
+ QQmlComponent component(&engine, testFileUrl("functionAssignment.1.qml"));
+
+ QString url = component.url().toString();
+ QString warning = url + ":4: Unable to assign a function to a property.";
+ QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
+
+ MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(o != 0);
+
+ QVERIFY(!o->property("a").isValid());
+
+ delete o;
+}
+
+void tst_qqmlecmascript::functionAssignment_fromJS()
+{
+ QFETCH(QString, triggerProperty);
+
+ 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->property("a").isValid());
+
+ o->setProperty("aNumber", QVariant(5));
+ o->setProperty(triggerProperty.toUtf8().constData(), true);
+ QCOMPARE(o->property("a"), QVariant(50));
+
+ o->setProperty("aNumber", QVariant(10));
+ QCOMPARE(o->property("a"), QVariant(100));
+
+ delete o;
+}
+
+void tst_qqmlecmascript::functionAssignment_fromJS_data()
+{
+ QTest::addColumn<QString>("triggerProperty");
+
+ QTest::newRow("assign to property") << "assignToProperty";
+ QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
+
+ QTest::newRow("assign to value type") << "assignToValueType";
+
+ QTest::newRow("use 'this'") << "assignWithThis";
+ QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
+}
+
+void tst_qqmlecmascript::functionAssignmentfromJS_invalid()
+{
+ 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->property("a").isValid());
+
+ o->setProperty("assignFuncWithoutReturn", true);
+ QVERIFY(!o->property("a").isValid());
+
+ QString url = component.url().toString();
+ QString warning = url + ":67: Unable to assign QString to int";
+ QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
+ o->setProperty("assignWrongType", true);
+
+ warning = url + ":71: Unable to assign QString to int";
+ QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
+ o->setProperty("assignWrongTypeToValueType", true);
+
+ delete o;
+}
+
+void tst_qqmlecmascript::eval()
+{
+ QQmlComponent component(&engine, testFileUrl("eval.qml"));
+
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ QCOMPARE(o->property("test1").toBool(), true);
+ QCOMPARE(o->property("test2").toBool(), true);
+ QCOMPARE(o->property("test3").toBool(), true);
+ QCOMPARE(o->property("test4").toBool(), true);
+ QCOMPARE(o->property("test5").toBool(), true);
+
+ delete o;
+}
+
+void tst_qqmlecmascript::function()
+{
+ QQmlComponent component(&engine, testFileUrl("function.qml"));
+
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ QCOMPARE(o->property("test1").toBool(), true);
+ QCOMPARE(o->property("test2").toBool(), true);
+ QCOMPARE(o->property("test3").toBool(), true);
+
+ delete o;
+}
+
+void tst_qqmlecmascript::functionException()
+{
+ // QTBUG-24037 - shouldn't crash.
+ QString errstr = testFileUrl("v8functionException.qml").toString() + QLatin1String(":13: SyntaxError: Unexpected token ILLEGAL");
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(errstr));
+ QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: Exception occurred during compilation of function: dynamicSlot()");
+ QQmlComponent component(&engine, testFileUrl("v8functionException.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+ QMetaObject::invokeMethod(o, "dynamicSlot");
+ delete o;
+}
+
+// Test the "Qt.include" method
+void tst_qqmlecmascript::include()
+{
+ // Non-library relative include
+ {
+ QQmlComponent component(&engine, testFileUrl("include.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ QCOMPARE(o->property("test0").toInt(), 99);
+ QCOMPARE(o->property("test1").toBool(), true);
+ QCOMPARE(o->property("test2").toBool(), true);
+ QCOMPARE(o->property("test2_1").toBool(), true);
+ QCOMPARE(o->property("test3").toBool(), true);
+ QCOMPARE(o->property("test3_1").toBool(), true);
+
+ delete o;
+ }
+
+ // Library relative include
+ {
+ QQmlComponent component(&engine, testFileUrl("include_shared.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ QCOMPARE(o->property("test0").toInt(), 99);
+ QCOMPARE(o->property("test1").toBool(), true);
+ QCOMPARE(o->property("test2").toBool(), true);
+ QCOMPARE(o->property("test2_1").toBool(), true);
+ QCOMPARE(o->property("test3").toBool(), true);
+ QCOMPARE(o->property("test3_1").toBool(), true);
+
+ delete o;
+ }
+
+ // Callback
+ {
+ QQmlComponent component(&engine, testFileUrl("include_callback.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ QCOMPARE(o->property("test1").toBool(), true);
+ QCOMPARE(o->property("test2").toBool(), true);
+ QCOMPARE(o->property("test3").toBool(), true);
+ QCOMPARE(o->property("test4").toBool(), true);
+ QCOMPARE(o->property("test5").toBool(), true);
+ QCOMPARE(o->property("test6").toBool(), true);
+
+ delete o;
+ }
+
+ // Including file with ".pragma library"
+ {
+ QQmlComponent component(&engine, testFileUrl("include_pragma.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+ QCOMPARE(o->property("test1").toInt(), 100);
+
+ delete o;
+ }
+
+ // Remote - success
+ {
+ TestHTTPServer server(8111);
+ QVERIFY(server.isValid());
+ server.serveDirectory(dataDirectory());
+
+ QQmlComponent component(&engine, testFileUrl("include_remote.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ QTRY_VERIFY(o->property("done").toBool() == true);
+ QTRY_VERIFY(o->property("done2").toBool() == true);
+
+ QCOMPARE(o->property("test1").toBool(), true);
+ QCOMPARE(o->property("test2").toBool(), true);
+ QCOMPARE(o->property("test3").toBool(), true);
+ QCOMPARE(o->property("test4").toBool(), true);
+ QCOMPARE(o->property("test5").toBool(), true);
+
+ QCOMPARE(o->property("test6").toBool(), true);
+ QCOMPARE(o->property("test7").toBool(), true);
+ QCOMPARE(o->property("test8").toBool(), true);
+ QCOMPARE(o->property("test9").toBool(), true);
+ QCOMPARE(o->property("test10").toBool(), true);
+
+ delete o;
+ }
+
+ // Remote - error
+ {
+ TestHTTPServer server(8111);
+ QVERIFY(server.isValid());
+ server.serveDirectory(dataDirectory());
+
+ QQmlComponent component(&engine, testFileUrl("include_remote_missing.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ QTRY_VERIFY(o->property("done").toBool() == true);
+
+ QCOMPARE(o->property("test1").toBool(), true);
+ QCOMPARE(o->property("test2").toBool(), true);
+ QCOMPARE(o->property("test3").toBool(), true);
+
+ delete o;
+ }
+}
+
+void tst_qqmlecmascript::signalHandlers()
+{
+ QQmlComponent component(&engine, testFileUrl("signalHandlers.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ QVERIFY(o->property("count").toInt() == 0);
+ QMetaObject::invokeMethod(o, "testSignalCall");
+ QCOMPARE(o->property("count").toInt(), 1);
+
+ QMetaObject::invokeMethod(o, "testSignalHandlerCall");
+ QCOMPARE(o->property("count").toInt(), 1);
+ QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
+
+ QVERIFY(o->property("funcCount").toInt() == 0);
+ QMetaObject::invokeMethod(o, "testSignalConnection");
+ QCOMPARE(o->property("funcCount").toInt(), 1);
+
+ QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
+ QCOMPARE(o->property("funcCount").toInt(), 2);
+
+ QMetaObject::invokeMethod(o, "testSignalDefined");
+ QCOMPARE(o->property("definedResult").toBool(), true);
+
+ QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
+ QCOMPARE(o->property("definedHandlerResult").toBool(), true);
+
+ delete o;
+}
+
+void tst_qqmlecmascript::qtbug_10696()
+{
+ QQmlComponent component(&engine, testFileUrl("qtbug_10696.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+ delete o;
+}
+
+void tst_qqmlecmascript::qtbug_11606()
+{
+ QQmlComponent component(&engine, testFileUrl("qtbug_11606.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+ QCOMPARE(o->property("test").toBool(), true);
+ delete o;
+}
+
+void tst_qqmlecmascript::qtbug_11600()
+{
+ QQmlComponent component(&engine, testFileUrl("qtbug_11600.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+ QCOMPARE(o->property("test").toBool(), true);
+ delete o;
+}
+
+void tst_qqmlecmascript::qtbug_21864()
+{
+ QQmlComponent component(&engine, testFileUrl("qtbug_21864.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+ QCOMPARE(o->property("test").toBool(), true);
+ delete o;
+}
+
+void tst_qqmlecmascript::rewriteMultiLineStrings()
+{
+ {
+ // QTBUG-23387
+ QQmlComponent component(&engine, testFileUrl("rewriteMultiLineStrings.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+ QTRY_COMPARE(o->property("test").toBool(), true);
+ delete o;
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("rewriteMultiLineStrings_crlf.1.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+ delete o;
+ }
+}
+
+void tst_qqmlecmascript::qobjectConnectionListExceptionHandling()
+{
+ // QTBUG-23375
+ 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);
+ QCOMPARE(o->property("test").toBool(), true);
+ delete o;
+}
+
+// Reading and writing non-scriptable properties should fail
+void tst_qqmlecmascript::nonscriptable()
+{
+ QQmlComponent component(&engine, testFileUrl("nonscriptable.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+ QCOMPARE(o->property("readOk").toBool(), true);
+ QCOMPARE(o->property("writeOk").toBool(), true);
+ delete o;
+}
+
+// deleteLater() should not be callable from QML
+void tst_qqmlecmascript::deleteLater()
+{
+ QQmlComponent component(&engine, testFileUrl("deleteLater.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+ QCOMPARE(o->property("test").toBool(), true);
+ delete o;
+}
+
+void tst_qqmlecmascript::in()
+{
+ QQmlComponent component(&engine, testFileUrl("in.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+ QCOMPARE(o->property("test1").toBool(), true);
+ QCOMPARE(o->property("test2").toBool(), true);
+ delete o;
+}
+
+void tst_qqmlecmascript::typeOf()
+{
+ QQmlComponent component(&engine, testFileUrl("typeOf.qml"));
+
+ // These warnings should not happen once QTBUG-21864 is fixed
+ QString warning1 = component.url().toString() + QLatin1String(":16: Error: Cannot assign [undefined] to QString");
+ QString warning2 = component.url().resolved(QUrl("typeOf.js")).toString() + QLatin1String(":1: ReferenceError: Can't find variable: a");
+
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
+
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ QEXPECT_FAIL("", "QTBUG-21864", Abort);
+ QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
+ QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
+ QCOMPARE(o->property("test3").toString(), QLatin1String("number"));
+ QCOMPARE(o->property("test4").toString(), QLatin1String("string"));
+ QCOMPARE(o->property("test5").toString(), QLatin1String("function"));
+ QCOMPARE(o->property("test6").toString(), QLatin1String("object"));
+ QCOMPARE(o->property("test7").toString(), QLatin1String("undefined"));
+ QCOMPARE(o->property("test8").toString(), QLatin1String("boolean"));
+ QCOMPARE(o->property("test9").toString(), QLatin1String("object"));
+
+ delete o;
+}
+
+void tst_qqmlecmascript::sharedAttachedObject()
+{
+ QQmlComponent component(&engine, testFileUrl("sharedAttachedObject.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+ QCOMPARE(o->property("test1").toBool(), true);
+ QCOMPARE(o->property("test2").toBool(), true);
+ delete o;
+}
+
+// QTBUG-13999
+void tst_qqmlecmascript::objectName()
+{
+ QQmlComponent component(&engine, testFileUrl("objectName.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ QCOMPARE(o->property("test1").toString(), QString("hello"));
+ QCOMPARE(o->property("test2").toString(), QString("ell"));
+
+ o->setObjectName("world");
+
+ QCOMPARE(o->property("test1").toString(), QString("world"));
+ QCOMPARE(o->property("test2").toString(), QString("orl"));
+
+ delete o;
+}
+
+void tst_qqmlecmascript::writeRemovesBinding()
+{
+ QQmlComponent component(&engine, testFileUrl("writeRemovesBinding.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ QCOMPARE(o->property("test").toBool(), true);
+
+ delete o;
+}
+
+// Test bindings assigned to alias properties actually assign to the alias' target
+void tst_qqmlecmascript::aliasBindingsAssignCorrectly()
+{
+ QQmlComponent component(&engine, testFileUrl("aliasBindingsAssignCorrectly.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ QCOMPARE(o->property("test").toBool(), true);
+
+ delete o;
+}
+
+// Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
+void tst_qqmlecmascript::aliasBindingsOverrideTarget()
+{
+ {
+ QQmlComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ QCOMPARE(o->property("test").toBool(), true);
+
+ delete o;
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.2.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ QCOMPARE(o->property("test").toBool(), true);
+
+ delete o;
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.3.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ QCOMPARE(o->property("test").toBool(), true);
+
+ delete o;
+ }
+}
+
+// Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
+void tst_qqmlecmascript::aliasWritesOverrideBindings()
+{
+ {
+ QQmlComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ QCOMPARE(o->property("test").toBool(), true);
+
+ delete o;
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.2.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ QCOMPARE(o->property("test").toBool(), true);
+
+ delete o;
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.3.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ QCOMPARE(o->property("test").toBool(), true);
+
+ delete o;
+ }
+}
+
+// Allow an alais to a composite element
+// QTBUG-20200
+void tst_qqmlecmascript::aliasToCompositeElement()
+{
+ QQmlComponent component(&engine, testFileUrl("aliasToCompositeElement.qml"));
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ delete object;
+}
+
+void tst_qqmlecmascript::qtbug_20344()
+{
+ 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);
+
+ delete object;
+}
+
+void tst_qqmlecmascript::revisionErrors()
+{
+ {
+ QQmlComponent component(&engine, testFileUrl("metaobjectRevisionErrors.qml"));
+ QString url = component.url().toString();
+
+ QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
+ QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
+ QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
+
+ QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
+ QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
+ QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
+ MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
+ QVERIFY(object != 0);
+ delete object;
+ }
+ {
+ QQmlComponent component(&engine, testFileUrl("metaobjectRevisionErrors2.qml"));
+ QString url = component.url().toString();
+
+ // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
+ // method2, prop2 from MyRevisionedClass not available
+ // method4, prop4 from MyRevisionedSubclass not available
+ QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
+ QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
+ QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
+ QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
+ QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
+
+ QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
+ QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
+ QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
+ QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
+ QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
+ MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
+ QVERIFY(object != 0);
+ delete object;
+ }
+ {
+ QQmlComponent component(&engine, testFileUrl("metaobjectRevisionErrors3.qml"));
+ QString url = component.url().toString();
+
+ // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
+ // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
+ QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
+ QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
+ QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
+ QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
+ QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
+ QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
+ MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
+ QVERIFY(object != 0);
+ delete object;
+ }
+}
+
+void tst_qqmlecmascript::revision()
+{
+ {
+ QQmlComponent component(&engine, testFileUrl("metaobjectRevision.qml"));
+ QString url = component.url().toString();
+
+ MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
+ QVERIFY(object != 0);
+ delete object;
+ }
+ {
+ QQmlComponent component(&engine, testFileUrl("metaobjectRevision2.qml"));
+ QString url = component.url().toString();
+
+ MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
+ QVERIFY(object != 0);
+ delete object;
+ }
+ {
+ QQmlComponent component(&engine, testFileUrl("metaobjectRevision3.qml"));
+ QString url = component.url().toString();
+
+ MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
+ QVERIFY(object != 0);
+ delete object;
+ }
+ // Test that non-root classes can resolve revisioned methods
+ {
+ QQmlComponent component(&engine, testFileUrl("metaobjectRevision4.qml"));
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ QCOMPARE(object->property("test").toReal(), 11.);
+ delete object;
+ }
+}
+
+void tst_qqmlecmascript::realToInt()
+{
+ QQmlComponent component(&engine, testFileUrl("realToInt.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
+ QVERIFY(object != 0);
+
+ QMetaObject::invokeMethod(object, "test1");
+ QCOMPARE(object->value(), int(4));
+ QMetaObject::invokeMethod(object, "test2");
+ QCOMPARE(object->value(), int(8));
+}
+
+void tst_qqmlecmascript::urlProperty()
+{
+ {
+ QQmlComponent component(&engine, testFileUrl("urlProperty.1.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
+ QVERIFY(object != 0);
+ object->setStringProperty("http://qt-project.org");
+ QCOMPARE(object->urlProperty(), QUrl("http://qt-project.org/index.html"));
+ QCOMPARE(object->intProperty(), 123);
+ QCOMPARE(object->value(), 1);
+ QCOMPARE(object->property("result").toBool(), true);
+ }
+}
+
+void tst_qqmlecmascript::urlPropertyWithEncoding()
+{
+ {
+ QQmlComponent component(&engine, testFileUrl("urlProperty.2.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
+ QVERIFY(object != 0);
+ object->setStringProperty("http://qt-project.org");
+ QUrl encoded;
+ encoded.setEncodedUrl("http://qt-project.org/?get%3cDATA%3e", QUrl::TolerantMode);
+ QCOMPARE(object->urlProperty(), encoded);
+ QCOMPARE(object->value(), 0); // Interpreting URL as string yields canonicalised version
+ QCOMPARE(object->property("result").toBool(), true);
+ }
+}
+
+void tst_qqmlecmascript::urlListPropertyWithEncoding()
+{
+ {
+ QQmlComponent component(&engine, testFileUrl("urlListProperty.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ 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);
+ QUrl encoded;
+ encoded.setEncodedUrl("http://qt-project.org/?get%3cDATA%3e", QUrl::TolerantMode);
+ QCOMPARE(msco1->urlListProperty(), (QList<QUrl>() << encoded));
+ QCOMPARE(msco2->urlListProperty(), (QList<QUrl>() << encoded));
+ QCOMPARE(msco3->urlListProperty(), (QList<QUrl>() << encoded << encoded));
+ QCOMPARE(msco4->urlListProperty(), (QList<QUrl>() << encoded << encoded));
+ delete object;
+ }
+}
+
+void tst_qqmlecmascript::dynamicString()
+{
+ QQmlComponent component(&engine, testFileUrl("dynamicString.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ 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::automaticSemicolon()
+{
+ QQmlComponent component(&engine, testFileUrl("automaticSemicolon.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+}
+
+void tst_qqmlecmascript::unaryExpression()
+{
+ QQmlComponent component(&engine, testFileUrl("unaryExpression.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+}
+
+// Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
+void tst_qqmlecmascript::doubleEvaluate()
+{
+ QQmlComponent component(&engine, testFileUrl("doubleEvaluate.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ WriteCounter *wc = qobject_cast<WriteCounter *>(object);
+ QVERIFY(wc != 0);
+ QCOMPARE(wc->count(), 1);
+
+ wc->setProperty("x", 9);
+
+ QCOMPARE(wc->count(), 2);
+
+ delete object;
+}
+
+static QStringList messages;
+static void captureMsgHandler(QtMsgType, const char *msg)
+{
+ messages.append(QLatin1String(msg));
+}
+
+void tst_qqmlecmascript::nonNotifyable()
+{
+ QV4Compiler::enableV4(false);
+ QQmlComponent component(&engine, testFileUrl("nonNotifyable.qml"));
+ QV4Compiler::enableV4(true);
+
+ QtMsgHandler old = qInstallMsgHandler(captureMsgHandler);
+ messages.clear();
+ QObject *object = component.create();
+ qInstallMsgHandler(old);
+
+ QVERIFY(object != 0);
+
+ QString expected1 = QLatin1String("QQmlExpression: Expression ") +
+ component.url().toString() +
+ QLatin1String(":5 depends on non-NOTIFYable properties:");
+ QString expected2 = QLatin1String(" ") +
+ QLatin1String(object->metaObject()->className()) +
+ QLatin1String("::value");
+
+ QCOMPARE(messages.length(), 2);
+ QCOMPARE(messages.at(0), expected1);
+ QCOMPARE(messages.at(1), expected2);
+
+ delete object;
+}
+
+void tst_qqmlecmascript::forInLoop()
+{
+ QQmlComponent component(&engine, testFileUrl("forInLoop.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QMetaObject::invokeMethod(object, "listProperty");
+
+ QStringList r = object->property("listResult").toString().split("|", QString::SkipEmptyParts);
+ QCOMPARE(r.size(), 3);
+ QCOMPARE(r[0],QLatin1String("0=obj1"));
+ QCOMPARE(r[1],QLatin1String("1=obj2"));
+ QCOMPARE(r[2],QLatin1String("2=obj3"));
+
+ //TODO: should test for in loop for other objects (such as QObjects) as well.
+
+ delete object;
+}
+
+// An object the binding depends on is deleted while the binding is still running
+void tst_qqmlecmascript::deleteWhileBindingRunning()
+{
+ QQmlComponent component(&engine, testFileUrl("deleteWhileBindingRunning.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ delete object;
+}
+
+void tst_qqmlecmascript::qtbug_22679()
+{
+ MyQmlObject object;
+ object.setStringProperty(QLatin1String("Please work correctly"));
+ engine.rootContext()->setContextProperty("contextProp", &object);
+
+ QQmlComponent component(&engine, testFileUrl("qtbug_22679.qml"));
+ qRegisterMetaType<QList<QQmlError> >("QList<QQmlError>");
+ QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QQmlError>)));
+
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+ QCOMPARE(warningsSpy.count(), 0);
+ delete o;
+}
+
+void tst_qqmlecmascript::qtbug_22843_data()
+{
+ QTest::addColumn<bool>("library");
+
+ QTest::newRow("without .pragma library") << false;
+ QTest::newRow("with .pragma library") << true;
+}
+
+void tst_qqmlecmascript::qtbug_22843()
+{
+ QFETCH(bool, library);
+
+ QString fileName("qtbug_22843");
+ if (library)
+ fileName += QLatin1String(".library");
+ fileName += QLatin1String(".qml");
+
+ QQmlComponent component(&engine, testFileUrl(fileName));
+ QString url = component.url().toString();
+ QString warning1 = url.left(url.length()-3) + QLatin1String("js:4: SyntaxError: Unexpected token )");
+ QString warning2 = url + QLatin1String(":5: TypeError: Object [object Object] has no method 'func'");
+
+ qRegisterMetaType<QList<QQmlError> >("QList<QQmlError>");
+ QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QQmlError>)));
+ for (int x = 0; x < 3; ++x) {
+ warningsSpy.clear();
+ // For libraries, only the first import attempt should produce a
+ // SyntaxError warning; subsequent component creation should not
+ // attempt to reload the script.
+ bool expectSyntaxError = !library || (x == 0);
+ if (expectSyntaxError)
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ QCOMPARE(warningsSpy.count(), 1 + (expectSyntaxError?1:0));
+ delete object;
+ }
+}
+
+
+void tst_qqmlecmascript::switchStatement()
+{
+ {
+ QQmlComponent component(&engine, testFileUrl("switchStatement.1.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ // `object->value()' is the number of executed statements
+
+ object->setStringProperty("A");
+ QCOMPARE(object->value(), 5);
+
+ object->setStringProperty("S");
+ QCOMPARE(object->value(), 3);
+
+ object->setStringProperty("D");
+ QCOMPARE(object->value(), 3);
+
+ object->setStringProperty("F");
+ QCOMPARE(object->value(), 4);
+
+ object->setStringProperty("something else");
+ QCOMPARE(object->value(), 1);
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("switchStatement.2.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ // `object->value()' is the number of executed statements
+
+ object->setStringProperty("A");
+ QCOMPARE(object->value(), 5);
+
+ object->setStringProperty("S");
+ QCOMPARE(object->value(), 3);
+
+ object->setStringProperty("D");
+ QCOMPARE(object->value(), 3);
+
+ object->setStringProperty("F");
+ QCOMPARE(object->value(), 3);
+
+ object->setStringProperty("something else");
+ QCOMPARE(object->value(), 4);
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("switchStatement.3.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ // `object->value()' is the number of executed statements
+
+ object->setStringProperty("A");
+ QCOMPARE(object->value(), 5);
+
+ object->setStringProperty("S");
+ QCOMPARE(object->value(), 3);
+
+ object->setStringProperty("D");
+ QCOMPARE(object->value(), 3);
+
+ object->setStringProperty("F");
+ QCOMPARE(object->value(), 3);
+
+ object->setStringProperty("something else");
+ QCOMPARE(object->value(), 6);
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("switchStatement.4.qml"));
+
+ QString warning = component.url().toString() + ":4: Unable to assign [undefined] to int";
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
+
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ // `object->value()' is the number of executed statements
+
+ object->setStringProperty("A");
+ QCOMPARE(object->value(), 5);
+
+ object->setStringProperty("S");
+ QCOMPARE(object->value(), 3);
+
+ object->setStringProperty("D");
+ QCOMPARE(object->value(), 3);
+
+ object->setStringProperty("F");
+ QCOMPARE(object->value(), 3);
+
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
+
+ object->setStringProperty("something else");
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("switchStatement.5.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ // `object->value()' is the number of executed statements
+
+ object->setStringProperty("A");
+ QCOMPARE(object->value(), 1);
+
+ object->setStringProperty("S");
+ QCOMPARE(object->value(), 1);
+
+ object->setStringProperty("D");
+ QCOMPARE(object->value(), 1);
+
+ object->setStringProperty("F");
+ QCOMPARE(object->value(), 1);
+
+ object->setStringProperty("something else");
+ QCOMPARE(object->value(), 1);
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("switchStatement.6.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ // `object->value()' is the number of executed statements
+
+ object->setStringProperty("A");
+ QCOMPARE(object->value(), 123);
+
+ object->setStringProperty("S");
+ QCOMPARE(object->value(), 123);
+
+ object->setStringProperty("D");
+ QCOMPARE(object->value(), 321);
+
+ object->setStringProperty("F");
+ QCOMPARE(object->value(), 321);
+
+ object->setStringProperty("something else");
+ QCOMPARE(object->value(), 0);
+ }
+}
+
+void tst_qqmlecmascript::withStatement()
+{
+ {
+ QQmlComponent component(&engine, testFileUrl("withStatement.1.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->value(), 123);
+ }
+}
+
+void tst_qqmlecmascript::tryStatement()
+{
+ {
+ QQmlComponent component(&engine, testFileUrl("tryStatement.1.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->value(), 123);
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("tryStatement.2.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->value(), 321);
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("tryStatement.3.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->value(), 1);
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("tryStatement.4.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->value(), 1);
+ }
+}
+
+class CppInvokableWithQObjectDerived : public QObject
+{
+ Q_OBJECT
+public:
+ CppInvokableWithQObjectDerived() {}
+ ~CppInvokableWithQObjectDerived() {}
+
+ Q_INVOKABLE MyQmlObject *createMyQmlObject(QString data)
+ {
+ MyQmlObject *obj = new MyQmlObject();
+ obj->setStringProperty(data);
+ return obj;
+ }
+
+ Q_INVOKABLE QString getStringProperty(MyQmlObject *obj)
+ {
+ return obj->stringProperty();
+ }
+};
+
+void tst_qqmlecmascript::invokableWithQObjectDerived()
+{
+ CppInvokableWithQObjectDerived invokable;
+
+ {
+ QQmlEngine engine;
+ engine.rootContext()->setContextProperty("invokable", &invokable);
+
+ QQmlComponent component(&engine, testFileUrl("qobjectDerivedArgument.qml"));
+
+ QObject *object = component.create();
+
+ QVERIFY(object != 0);
+ QVERIFY(object->property("result").value<bool>() == true);
+
+ delete object;
+ }
+}
+
+QTEST_MAIN(tst_qqmlecmascript)
+
+#include "tst_qqmlecmascript.moc"