JSValue QtInstance::stringValue(ExecState* exec) const { QObject* obj = getObject(); if (!obj) return jsNull(); // Hmm.. see if there is a toString defined QByteArray buf; bool useDefault = true; getClass(); if (m_class) { // Cheat and don't use the full name resolution int index = obj->metaObject()->indexOfMethod("toString()"); if (index >= 0) { QMetaMethod m = obj->metaObject()->method(index); // Check to see how much we can call it if (m.access() != QMetaMethod::Private && m.methodType() != QMetaMethod::Signal #if HAVE(QT5) && m.parameterCount() == 0 && m.returnType() != QMetaType::Void) { QVariant ret(m.returnType(), (void*)0); void * qargs[1]; qargs[0] = ret.data(); if (QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, index, qargs) < 0) { if (ret.isValid() && ret.canConvert(QVariant::String)) { buf = ret.toString().toLatin1().constData(); // ### Latin 1? Ascii? useDefault = false; #else && m.parameterTypes().isEmpty()) { const char* retsig = m.typeName(); if (retsig && *retsig) { QVariant ret(QMetaType::type(retsig), (void*)0); void * qargs[1]; qargs[0] = ret.data(); if (QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, index, qargs) < 0) { if (ret.isValid() && ret.canConvert(QVariant::String)) { buf = ret.toString().toLatin1().constData(); // ### Latin 1? Ascii? useDefault = false; } #endif } } } } } if (useDefault) { const QMetaObject* meta = obj ? obj->metaObject() : &QObject::staticMetaObject; QString name = obj ? obj->objectName() : QString::fromUtf8("unnamed"); QString str = QString::fromUtf8("%0(name = \"%1\")") .arg(QLatin1String(meta->className())).arg(name); buf = str.toLatin1(); } return jsString(exec, buf.constData()); }
int QDBusInterfacePrivate::metacall(QMetaObject::Call c, int id, void **argv) { Q_Q(QDBusInterface); if (c == QMetaObject::InvokeMetaMethod) { int offset = metaObject->methodOffset(); QMetaMethod mm = metaObject->method(id + offset); if (mm.methodType() == QMetaMethod::Signal) { // signal relay from D-Bus world to Qt world QMetaObject::activate(q, metaObject, id, argv); } else if (mm.methodType() == QMetaMethod::Slot || mm.methodType() == QMetaMethod::Method) { // method call relay from Qt world to D-Bus world // get D-Bus equivalent signature QString methodName = QString::fromLatin1(mm.name()); const int *inputTypes = metaObject->inputTypesForMethod(id); int inputTypesCount = *inputTypes; // we will assume that the input arguments were passed correctly QVariantList args; args.reserve(inputTypesCount); int i = 1; for ( ; i <= inputTypesCount; ++i) args << QVariant(inputTypes[i], argv[i]); // make the call QDBusMessage reply = q->callWithArgumentList(QDBus::Block, methodName, args); if (reply.type() == QDBusMessage::ReplyMessage) { // attempt to demarshall the return values args = reply.arguments(); QVariantList::ConstIterator it = args.constBegin(); const int *outputTypes = metaObject->outputTypesForMethod(id); int outputTypesCount = *outputTypes++; if (mm.returnType() != QMetaType::UnknownType && mm.returnType() != QMetaType::Void) { // this method has a return type if (argv[0] && it != args.constEnd()) copyArgument(argv[0], *outputTypes++, *it); // skip this argument even if we didn't copy it --outputTypesCount; ++it; } for (int j = 0; j < outputTypesCount && it != args.constEnd(); ++i, ++j, ++it) { copyArgument(argv[i], outputTypes[j], *it); } } // done lastError = QDBusError(reply); return -1; } } return id; }
void Bindable::checkReturnType(const QMetaMethod &method, const int typeId) { Q_ASSERT_X(typeId != QMetaType::UnknownType, "Bindable::wait", "Requested return type is not registered, please use the Q_DECLARE_METATYPE " "macro to make it known to Qt's meta-object system"); Q_ASSERT_X( method.returnType() == typeId || QMetaType::hasRegisteredConverterFunction(method.returnType(), typeId), "Bindable::wait", qPrintable( QString("Requested return type (%1) is incompatible method return type (%2)") .arg(QMetaType::typeName(typeId), QMetaType::typeName(method.returnType())))); }
// Creates a string, describing an object, using meta-object introspection QString objToString(const QObject *obj) { QStringList result; const QMetaObject *meta = obj->metaObject(); result += QString("class %1 : public %2 {").arg(meta->className()) .arg(meta->superClass()->className()); for (auto i=0; i < meta->propertyCount(); ++i) { const QMetaProperty property = meta->property(i); QVariant value = obj->property(property.name()); if (value.canConvert(QVariant::String)) result += QString(" %1 %2 = %3;") .arg(property.typeName()) .arg(property.name()) .arg(value.toString()); } QString signalPrefix(""); for (auto i=0; i < meta->methodCount(); ++i) { const QMetaMethod method = meta->method(i); const QMetaMethod::MethodType methodType = method.methodType(); if (methodType == QMetaMethod::Signal) signalPrefix = QStringLiteral("Q_SIGNAL"); else if (methodType == QMetaMethod::Slot) signalPrefix = QStringLiteral("Q_SLOT"); result += QString(" %1 %2 %3;") .arg(signalPrefix) .arg(QVariant::typeToName(method.returnType())) .arg(QString(method.methodSignature())); } result += "};"; return result.join("\n"); }
void QDeclarativePropertyCache::Data::load(const QMetaMethod &m) { coreIndex = m.methodIndex(); relatedIndex = -1; flags |= Data::IsFunction; if (m.methodType() == QMetaMethod::Signal) flags |= Data::IsSignal; propType = m.returnType(); QList<QByteArray> params = m.parameterTypes(); if (!params.isEmpty()) flags |= Data::HasArguments; revision = m.revision(); }
error *objectInvoke(QObject_ *object, const char *method, int methodLen, DataValue *resultdv, DataValue *paramsdv, int paramsLen) { QObject *qobject = reinterpret_cast<QObject *>(object); QVariant result; QVariant param[MaxParams]; QGenericArgument arg[MaxParams]; for (int i = 0; i < paramsLen; i++) { unpackDataValue(¶msdv[i], ¶m[i]); arg[i] = Q_ARG(QVariant, param[i]); } if (paramsLen > 10) { panicf("fix the parameter dispatching"); } const QMetaObject *metaObject = qobject->metaObject(); // Walk backwards so descendants have priority. for (int i = metaObject->methodCount()-1; i >= 0; i--) { QMetaMethod metaMethod = metaObject->method(i); QMetaMethod::MethodType methodType = metaMethod.methodType(); if (methodType == QMetaMethod::Method || methodType == QMetaMethod::Slot) { QByteArray name = metaMethod.name(); if (name.length() == methodLen && qstrncmp(name.constData(), method, methodLen) == 0) { if (metaMethod.parameterCount() < paramsLen) { // TODO Might continue looking to see if a different signal has the same name and enough arguments. return errorf("method \"%s\" has too few parameters for provided arguments", method); } bool ok; if (metaMethod.returnType() == QMetaType::Void) { ok = metaMethod.invoke(qobject, Qt::DirectConnection, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9]); } else { ok = metaMethod.invoke(qobject, Qt::DirectConnection, Q_RETURN_ARG(QVariant, result), arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9]); } if (!ok) { return errorf("invalid parameters to method \"%s\"", method); } packDataValue(&result, resultdv); return 0; } } } return errorf("object does not expose a method \"%s\"", method); }
void Nuria::ObjectWrapperResourcePrivate::addMethodToPropertyList (QMetaMethod method, Method &descriptor) { Nuria::Resource::Property::Type type = (method.methodType () == QMetaMethod::Signal) ? Nuria::Resource::Property::Signal : Nuria::Resource::Property::Slot; QString name = QString::fromLatin1 (method.name ()); int resultType = method.returnType (); Nuria::Resource::ArgumentTypeMap args; // Convert descriptor to argument type map for (int i = 0; i < descriptor.names.length (); i++) { args.insert (descriptor.names.at (i), descriptor.types.at (i)); } // Add to list descriptor.propertyIndex = this->propertyList.length (); this->propertyList.append (Nuria::Resource::Property (type, name, args, resultType)); }
void tst_QQmlMetaObject::method() { QFETCH(QString, testFile); QFETCH(QString, signature); QFETCH(QMetaMethod::MethodType, methodType); QFETCH(int, returnType); QFETCH(QString, returnTypeName); QFETCH(QList<int>, parameterTypes); QFETCH(QList<QByteArray>, parameterTypeNames); QFETCH(QList<QByteArray>, parameterNames); QCOMPARE(parameterTypes.size(), parameterTypeNames.size()); QCOMPARE(parameterTypeNames.size(), parameterNames.size()); QQmlEngine engine; QQmlComponent component(&engine, testFileUrl(testFile)); QObject *object = component.create(); QVERIFY(object != 0); const QMetaObject *mo = object->metaObject(); QVERIFY(mo->superClass() != 0); QVERIFY(QByteArray(mo->className()).contains("_QML_")); QCOMPARE(mo->methodOffset(), mo->superClass()->methodCount()); QCOMPARE(mo->methodCount(), mo->superClass()->methodCount() + 1); QMetaMethod method = mo->method(mo->methodOffset()); QCOMPARE(method.methodType(), methodType); QCOMPARE(QString::fromUtf8(method.methodSignature().constData()), signature); QCOMPARE(method.access(), QMetaMethod::Public); QString computedName = signature.left(signature.indexOf('(')); QCOMPARE(QString::fromUtf8(method.name()), computedName); QCOMPARE(method.parameterCount(), parameterTypes.size()); for (int i = 0; i < parameterTypes.size(); ++i) QCOMPARE(method.parameterType(i), parameterTypes.at(i)); QCOMPARE(method.parameterTypes(), parameterTypeNames); QCOMPARE(method.tag(), ""); QCOMPARE(QString::fromUtf8(method.typeName()), returnTypeName); QCOMPARE(method.returnType(), returnType); delete object; }
void QObjectHandler::process(QHttpSocket *socket, const QString &path) { // Only POST requests are accepted - reject any other methods but ensure // that the Allow header is set in order to comply with RFC 2616 if(socket->method() != "POST") { socket->setHeader("Allow", "POST"); socket->writeError(QHttpSocket::MethodNotAllowed); return; } // Determine the index of the slot with the specified name - note that we // don't need to worry about retrieving the index for deleteLater() since // we specify the "QVariantMap" parameter type, which no parent slots use int index = metaObject()->indexOfSlot(QString("%1(QVariantMap)").arg(path).toUtf8().data()); // If the index is invalid, the "resource" was not found if(index == -1) { socket->writeError(QHttpSocket::NotFound); return; } // Ensure that the return type of the slot is QVariantMap QMetaMethod method = metaObject()->method(index); if(method.returnType() != QMetaType::QVariantMap) { socket->writeError(QHttpSocket::InternalServerError); return; } // Check to see if the socket has finished receiving all of the data yet // or not - if so, jump to invokeSlot(), otherwise wait for the // readChannelFinished() signal if(socket->bytesAvailable() >= socket->contentLength()) { d->invokeSlot(socket, index); } else { // Add the socket and index to the map so that the latter can be // retrieved when the readChannelFinished() signal is emitted d->map.insert(socket, index); connect(socket, SIGNAL(readChannelFinished()), d, SLOT(onReadChannelFinished())); } }
void tst_QMetaMethod::method() { QFETCH(QByteArray, signature); QFETCH(int, returnType); QFETCH(QByteArray, returnTypeName); QFETCH(QList<int>, parameterTypes); QFETCH(QList<QByteArray>, parameterTypeNames); QFETCH(QList<QByteArray>, parameterNames); QFETCH(QMetaMethod::MethodType, methodType); QFETCH(QMetaMethod::Access, access); QVERIFY(parameterTypes.size() == parameterTypeNames.size()); QVERIFY(parameterTypes.size() == parameterNames.size()); const QMetaObject *mo = &MethodTestObject::staticMetaObject; int index = (methodType == QMetaMethod::Constructor) ? mo->indexOfConstructor(signature) : mo->indexOfMethod(signature); QVERIFY(index != -1); QMetaMethod method = (methodType == QMetaMethod::Constructor) ? mo->constructor(index) : mo->method(index); QVERIFY(method.isValid()); QCOMPARE(method.methodType(), methodType); QCOMPARE(method.access(), access); QVERIFY(!method.methodSignature().isEmpty()); if (method.methodSignature() != signature) { // QMetaMethod should always produce a semantically equivalent signature int signatureIndex = (methodType == QMetaMethod::Constructor) ? mo->indexOfConstructor(method.methodSignature()) : mo->indexOfMethod(method.methodSignature()); QCOMPARE(signatureIndex, index); } QByteArray computedName = signature.left(signature.indexOf('(')); QCOMPARE(method.name(), computedName); QCOMPARE(method.tag(), ""); QCOMPARE(method.returnType(), returnType); QVERIFY(method.typeName() != 0); if (QByteArray(method.typeName()) != returnTypeName) { // QMetaMethod should always produce a semantically equivalent typename QCOMPARE(QMetaType::type(method.typeName()), QMetaType::type(returnTypeName)); } if (method.parameterTypes() != parameterTypeNames) { // QMetaMethod should always produce semantically equivalent typenames QList<QByteArray> actualTypeNames = method.parameterTypes(); QCOMPARE(actualTypeNames.size(), parameterTypeNames.size()); for (int i = 0; i < parameterTypeNames.size(); ++i) { QCOMPARE(QMetaType::type(actualTypeNames.at(i)), QMetaType::type(parameterTypeNames.at(i))); } } QCOMPARE(method.parameterNames(), parameterNames); QCOMPARE(method.parameterCount(), parameterTypes.size()); for (int i = 0; i < parameterTypes.size(); ++i) QCOMPARE(method.parameterType(i), parameterTypes.at(i)); { QVector<int> actualParameterTypes(parameterTypes.size()); method.getParameterTypes(actualParameterTypes.data()); for (int i = 0; i < parameterTypes.size(); ++i) QCOMPARE(actualParameterTypes.at(i), parameterTypes.at(i)); } // Bogus indexes QCOMPARE(method.parameterType(-1), 0); QCOMPARE(method.parameterType(parameterTypes.size()), 0); }
static QString generateInterfaceXml(const QMetaObject *mo, int flags, int methodOffset, int propOffset) { QString retval; // start with properties: if (flags & (QDBusConnection::ExportScriptableProperties | QDBusConnection::ExportNonScriptableProperties)) { for (int i = propOffset; i < mo->propertyCount(); ++i) { static const char *accessvalues[] = {0, "read", "write", "readwrite"}; QMetaProperty mp = mo->property(i); if (!((mp.isScriptable() && (flags & QDBusConnection::ExportScriptableProperties)) || (!mp.isScriptable() && (flags & QDBusConnection::ExportNonScriptableProperties)))) continue; int access = 0; if (mp.isReadable()) access |= 1; if (mp.isWritable()) access |= 2; int typeId = mp.userType(); if (!typeId) continue; const char *signature = QDBusMetaType::typeToSignature(typeId); if (!signature) continue; retval += QString::fromLatin1(" <property name=\"%1\" type=\"%2\" access=\"%3\"") .arg(QLatin1String(mp.name())) .arg(QLatin1String(signature)) .arg(QLatin1String(accessvalues[access])); if (QDBusMetaType::signatureToType(signature) == QVariant::Invalid) { const char *typeName = QMetaType::typeName(typeId); retval += QString::fromLatin1(">\n <annotation name=\"org.qtproject.QtDBus.QtTypeName\" value=\"%3\"/>\n </property>\n") .arg(typeNameToXml(typeName)); } else { retval += QLatin1String("/>\n"); } } } // now add methods: for (int i = methodOffset; i < mo->methodCount(); ++i) { QMetaMethod mm = mo->method(i); bool isSignal; if (mm.methodType() == QMetaMethod::Signal) // adding a signal isSignal = true; else if (mm.access() == QMetaMethod::Public && (mm.methodType() == QMetaMethod::Slot || mm.methodType() == QMetaMethod::Method)) isSignal = false; else continue; // neither signal nor public slot if (isSignal && !(flags & (QDBusConnection::ExportScriptableSignals | QDBusConnection::ExportNonScriptableSignals))) continue; // we're not exporting any signals if (!isSignal && (!(flags & (QDBusConnection::ExportScriptableSlots | QDBusConnection::ExportNonScriptableSlots)) && !(flags & (QDBusConnection::ExportScriptableInvokables | QDBusConnection::ExportNonScriptableInvokables)))) continue; // we're not exporting any slots or invokables QString xml = QString::fromLatin1(" <%1 name=\"%2\">\n") .arg(isSignal ? QLatin1String("signal") : QLatin1String("method")) .arg(QString::fromLatin1(mm.name())); // check the return type first int typeId = mm.returnType(); if (typeId != QMetaType::UnknownType && typeId != QMetaType::Void) { const char *typeName = QDBusMetaType::typeToSignature(typeId); if (typeName) { xml += QString::fromLatin1(" <arg type=\"%1\" direction=\"out\"/>\n") .arg(typeNameToXml(typeName)); // do we need to describe this argument? if (QDBusMetaType::signatureToType(typeName) == QVariant::Invalid) xml += QString::fromLatin1(" <annotation name=\"org.qtproject.QtDBus.QtTypeName.Out0\" value=\"%1\"/>\n") .arg(typeNameToXml(QMetaType::typeName(typeId))); } else { qWarning() << "Unsupported return type" << typeId << QMetaType::typeName(typeId) << "in method" << mm.name(); continue; } } else if (typeId == QMetaType::UnknownType) { qWarning() << "Invalid return type in method" << mm.name(); continue; // wasn't a valid type } QList<QByteArray> names = mm.parameterNames(); QVector<int> types; QString errorMsg; int inputCount = qDBusParametersForMethod(mm, types, errorMsg); if (inputCount == -1) { qWarning() << "Skipped method" << mm.name() << ":" << qPrintable(errorMsg); continue; // invalid form } if (isSignal && inputCount + 1 != types.count()) continue; // signal with output arguments? if (isSignal && types.at(inputCount) == QDBusMetaTypeId::message()) continue; // signal with QDBusMessage argument? if (isSignal && mm.attributes() & QMetaMethod::Cloned) continue; // cloned signal? int j; bool isScriptable = mm.attributes() & QMetaMethod::Scriptable; for (j = 1; j < types.count(); ++j) { // input parameter for a slot or output for a signal if (types.at(j) == QDBusMetaTypeId::message()) { isScriptable = true; continue; } QString name; if (!names.at(j - 1).isEmpty()) name = QString::fromLatin1("name=\"%1\" ").arg(QLatin1String(names.at(j - 1))); bool isOutput = isSignal || j > inputCount; const char *signature = QDBusMetaType::typeToSignature(types.at(j)); xml += QString::fromLatin1(" <arg %1type=\"%2\" direction=\"%3\"/>\n") .arg(name) .arg(QLatin1String(signature)) .arg(isOutput ? QLatin1String("out") : QLatin1String("in")); // do we need to describe this argument? if (QDBusMetaType::signatureToType(signature) == QVariant::Invalid) { const char *typeName = QMetaType::typeName(types.at(j)); xml += QString::fromLatin1(" <annotation name=\"org.qtproject.QtDBus.QtTypeName.%1%2\" value=\"%3\"/>\n") .arg(isOutput ? QLatin1String("Out") : QLatin1String("In")) .arg(isOutput && !isSignal ? j - inputCount : j - 1) .arg(typeNameToXml(typeName)); } } int wantedMask; if (isScriptable) wantedMask = isSignal ? QDBusConnection::ExportScriptableSignals : QDBusConnection::ExportScriptableSlots; else wantedMask = isSignal ? QDBusConnection::ExportNonScriptableSignals : QDBusConnection::ExportNonScriptableSlots; if ((flags & wantedMask) != wantedMask) continue; if (qDBusCheckAsyncTag(mm.tag())) // add the no-reply annotation xml += QLatin1String(" <annotation name=\"" ANNOTATION_NO_WAIT "\"" " value=\"true\"/>\n"); retval += xml; retval += QString::fromLatin1(" </%1>\n") .arg(isSignal ? QLatin1String("signal") : QLatin1String("method")); } return retval; }
int QServiceProxy::qt_metacall(QMetaObject::Call c, int id, void **a) { id = QServiceProxyBase::qt_metacall(c, id, a); if (id < 0 || !d->meta) return id; if (c == QMetaObject::InvokeMetaMethod) { const int mcount = d->meta->methodCount() - d->meta->methodOffset(); const int metaIndex = id + d->meta->methodOffset(); QMetaMethod method = d->meta->method(metaIndex); const int returnType = method.returnType(); //process arguments const QList<QByteArray> pTypes = method.parameterTypes(); const int pTypesCount = pTypes.count(); QVariantList args ; if (pTypesCount > 10) { qWarning() << "Cannot call" << method.methodSignature() << ". More than 10 parameter."; return id; } for (int i=0; i < pTypesCount; i++) { const QByteArray& t = pTypes[i]; int variantType = QMetaType::type(t); if (variantType == QMetaType::QVariant) { //ignore whether QVariant is declared as metatype args << *reinterpret_cast<const QVariant(*)>(a[i+1]); } else if ( variantType == 0 ){ qWarning("%s: argument %s has unknown type. Use qRegisterMetaType to register it.", method.methodSignature().constData(), t.data()); return id; } else { args << QVariant(variantType, a[i+1]); } } if (returnType == QMetaType::Void) { qServiceLog() << "event" << "nonblocking void call" << "method" << QString::fromLatin1(method.methodSignature()) << "endpoint" << d->endPoint->objectName(); d->endPoint->invokeRemote(d->localToRemote[metaIndex], args, returnType); } else { //TODO: invokeRemote() parameter list needs review qServiceLog() << "event" << "nonblocking call" << "method" << QString::fromLatin1(method.methodSignature()) << "endpoint" << d->endPoint->objectName(); QVariant result = d->endPoint->invokeRemote(d->localToRemote[metaIndex], args, returnType); if (result.type() != QVariant::Invalid){ if (returnType != QMetaType::QVariant) { QByteArray buffer; QDataStream stream(&buffer, QIODevice::ReadWrite); QMetaType::save(stream, returnType, result.constData()); stream.device()->seek(0); QMetaType::load(stream, returnType, a[0]); } else { if (a[0]) *reinterpret_cast< QVariant*>(a[0]) = result; } } } id-=mcount; } else if ( c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty || c == QMetaObject::ResetProperty ) { const int pCount = d->meta->propertyCount() - d->meta->propertyOffset(); const int metaIndex = id + d->meta->propertyOffset(); QMetaProperty property = d->meta->property(metaIndex); if (property.isValid()) { int pType = property.userType(); QVariant arg; if ( c == QMetaObject::WriteProperty ) { qServiceLog() << "event" << "property write" << "property" << property.name() << "endpoint" << d->endPoint->objectName(); if (pType == QMetaType::QVariant) arg = *reinterpret_cast<const QVariant(*)>(a[0]); else if (pType == 0) { qWarning("%s: property %s has unkown type", property.name(), property.typeName()); return id; } else { arg = QVariant(pType, a[0]); } } QVariant result; if (c == QMetaObject::ReadProperty) { qServiceLog() << "event" << "property read" << "property" << property.name() << "endpoint" << d->endPoint->objectName(); result = d->endPoint->invokeRemoteProperty(metaIndex, arg, pType, c); //wrap result for client if (pType != 0) { QByteArray buffer; QDataStream stream(&buffer, QIODevice::ReadWrite); QMetaType::save(stream, pType, result.constData()); stream.device()->seek(0); QMetaType::load(stream, pType, a[0]); } else { if (a[0]) *reinterpret_cast< QVariant*>(a[0]) = result; } } else { d->endPoint->invokeRemoteProperty(metaIndex, arg, pType, c); } } id-=pCount; } else if ( c == QMetaObject::QueryPropertyDesignable || c == QMetaObject::QueryPropertyScriptable || c == QMetaObject::QueryPropertyStored || c == QMetaObject::QueryPropertyEditable || c == QMetaObject::QueryPropertyUser ) { //Nothing to do? //These values are part of the transferred meta object already } else { //TODO qWarning() << "MetaCall type" << c << "not yet handled"; } return id; }
void tst_QQmlMetaObject::property() { QFETCH(QString, testFile); QFETCH(QByteArray, cppTypeName); QFETCH(int, cppType); QFETCH(bool, isDefault); QFETCH(QVariant, expectedValue); QFETCH(bool, isWritable); QFETCH(QVariant, newValue); QQmlEngine engine; QQmlComponent component(&engine, testFileUrl(testFile)); QObject *object = component.create(); QVERIFY(object != 0); const QMetaObject *mo = object->metaObject(); QVERIFY(mo->superClass() != 0); QVERIFY(QByteArray(mo->className()).contains("_QML_")); QCOMPARE(mo->propertyOffset(), mo->superClass()->propertyCount()); QCOMPARE(mo->propertyCount(), mo->superClass()->propertyCount() + 1); QMetaProperty prop = mo->property(mo->propertyOffset()); QCOMPARE(prop.name(), "test"); QCOMPARE(QByteArray(prop.typeName()), cppTypeName); if (prop.userType() < QMetaType::User) QCOMPARE(prop.type(), QVariant::Type(cppType)); else QCOMPARE(prop.type(), QVariant::UserType); QCOMPARE(prop.userType(), cppType); QVERIFY(!prop.isConstant()); QVERIFY(!prop.isDesignable()); QVERIFY(!prop.isEnumType()); QVERIFY(!prop.isFinal()); QVERIFY(!prop.isFlagType()); QVERIFY(prop.isReadable()); QVERIFY(!prop.isResettable()); QVERIFY(prop.isScriptable()); QVERIFY(!prop.isStored()); QVERIFY(!prop.isUser()); QVERIFY(prop.isValid()); QCOMPARE(prop.isWritable(), isWritable); QCOMPARE(mo->classInfoOffset(), mo->superClass()->classInfoCount()); QCOMPARE(mo->classInfoCount(), mo->superClass()->classInfoCount() + (isDefault ? 1 : 0)); if (isDefault) { QMetaClassInfo info = mo->classInfo(mo->classInfoOffset()); QCOMPARE(info.name(), "DefaultProperty"); QCOMPARE(info.value(), "test"); } QCOMPARE(mo->methodOffset(), mo->superClass()->methodCount()); QCOMPARE(mo->methodCount(), mo->superClass()->methodCount() + 1); // the signal QVERIFY(prop.notifySignalIndex() != -1); QMetaMethod signal = prop.notifySignal(); QCOMPARE(signal.methodType(), QMetaMethod::Signal); QCOMPARE(signal.name(), QByteArray("testChanged")); QCOMPARE(signal.methodSignature(), QByteArray("testChanged()")); QCOMPARE(signal.access(), QMetaMethod::Public); QCOMPARE(signal.parameterCount(), 0); QCOMPARE(signal.parameterTypes(), QList<QByteArray>()); QCOMPARE(signal.parameterNames(), QList<QByteArray>()); QCOMPARE(signal.tag(), ""); QCOMPARE(signal.typeName(), "void"); QCOMPARE(signal.returnType(), int(QMetaType::Void)); QSignalSpy changedSpy(object, SIGNAL(testChanged())); QObject::connect(object, SIGNAL(testChanged()), object, SLOT(deleteLater())); if (expectedValue.isValid()) QCOMPARE(prop.read(object), expectedValue); else QVERIFY(prop.read(object).isValid()); QCOMPARE(changedSpy.count(), 0); if (isWritable) { QVERIFY(prop.write(object, newValue)); QCOMPARE(changedSpy.count(), 1); QCOMPARE(prop.read(object), newValue); } else { QVERIFY(!prop.write(object, prop.read(object))); QCOMPARE(changedSpy.count(), 0); } delete object; }