File indexing completed on 2024-04-21 15:02:56

0001 /* This file is part of the KDE frameworks
0002     Copyright (c) 2015 David Faure <faure@kde.org>
0003 
0004     This library is free software; you can redistribute it and/or modify
0005     it under the terms of the GNU Lesser General Public License as published by
0006     the Free Software Foundation; either version 2 of the License or ( at
0007     your option ) version 3 or, at the discretion of KDE e.V. ( which shall
0008     act as a proxy as in section 14 of the GPLv3 ), any later version.
0009 
0010     This library is distributed in the hope that it will be useful,
0011     but WITHOUT ANY WARRANTY; without even the implied warranty of
0012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013     Library General Public License for more details.
0014 
0015     You should have received a copy of the GNU Lesser General Public License
0016     along with this library; see the file COPYING.LIB.  If not, write to
0017     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018     Boston, MA 02110-1301, USA.
0019 */
0020 
0021 #include <QDebug>
0022 #include <kross/core/metafunction.h>
0023 #include <QMetaMethod>
0024 #include <QTest>
0025 
0026 class MyFunction : public Kross::MetaFunction
0027 {
0028 public:
0029     MyFunction(QObject* sender, const QByteArray& signal)
0030         : Kross::MetaFunction(sender, signal) {}
0031 
0032     int qt_metacall(QMetaObject::Call _c, int _id, void **_a) override {
0033         _id = QObject::qt_metacall(_c, _id, _a);
0034         if (_id >= 0 && _c == QMetaObject::InvokeMetaMethod) {
0035             switch (_id) {
0036                 case 0:
0037                 {
0038                     // convert the arguments
0039                     QMetaMethod method = metaObject()->method( metaObject()->indexOfMethod(m_signature.constData()) );
0040                     m_paramTypes = method.parameterTypes();
0041                     for (int idx = 0; idx < m_paramTypes.size(); ++idx) {
0042                         const int tp = QVariant::nameToType( m_paramTypes.at(idx).constData() );
0043                         QVariant v(tp, _a[idx+1]);
0044                         m_paramValues.append(v);
0045                     }
0046                 }
0047             }
0048             _id -= 1;
0049         }
0050         return _id;
0051     }
0052     QList<QByteArray> paramTypes() const { return m_paramTypes; }
0053     QList<QVariant> paramValues() const { return m_paramValues; }
0054 private:
0055     QList<QByteArray> m_paramTypes;
0056     QList<QVariant> m_paramValues;
0057 };
0058 
0059 class WrappedObject : public QObject
0060 {
0061     Q_OBJECT
0062 public:
0063     void doEmit() { emit valueChanged(42); }
0064 Q_SIGNALS:
0065     void valueChanged(int);
0066 };
0067 
0068 class MetaFunctionTest : public QObject
0069 {
0070     Q_OBJECT
0071 private Q_SLOTS:
0072     void testMetaFunction()
0073     {
0074         WrappedObject obj;
0075         QList<MyFunction *> funcs;
0076         // mostly from kross-interpreters/python/pythonscript.cpp
0077         const QMetaObject* metaobject = obj.metaObject();
0078         const int count = metaobject->methodCount();
0079         for(int i = 0; i < count; ++i) {
0080             QMetaMethod metamethod = metaobject->method(i);
0081             if( metamethod.methodType() == QMetaMethod::Signal ) {
0082                 const QByteArray signature = metamethod.methodSignature();
0083                 // skip signals from QObject
0084                 if (signature.startsWith("destroyed") || signature.startsWith("objectNameChanged"))
0085                     continue;
0086                 MyFunction *func = new MyFunction(&obj, signature);
0087                 funcs.append(func);
0088                 const QByteArray name = signature.left(signature.indexOf('('));
0089                 QByteArray sendersignal = signature;
0090                 sendersignal.prepend(QSIGNAL_CODE + '0');
0091                 QByteArray receiverslot = signature;
0092                 receiverslot.prepend(QSLOT_CODE + '0');
0093 
0094                 QObject::connect(&obj, sendersignal.constData(), func, receiverslot.constData());
0095             }
0096         }
0097 
0098         QCOMPARE(funcs.count(), 1); // valueChanged
0099 
0100         MyFunction* valueChangedFunc = funcs.at(0);
0101         const QMetaObject *valueChangedMetaObj = valueChangedFunc->metaObject();
0102         bool found = false;
0103         QByteArray foundSig;
0104         for (int i = 0; i < valueChangedMetaObj->methodCount(); ++i) {
0105             QMetaMethod method = valueChangedMetaObj->method(i);
0106             if (method.name() == "valueChanged") {
0107                 found = true;
0108                 foundSig = method.methodSignature();
0109             }
0110         }
0111         QVERIFY2(found, "no valueChanged method/slot found in dynamic meta object!");
0112         QCOMPARE(foundSig.constData(), "valueChanged(int)");
0113 
0114         obj.doEmit();
0115         QCOMPARE(funcs.at(0)->paramTypes(), QList<QByteArray>() << "int");
0116         QCOMPARE(funcs.at(0)->paramValues().at(0).toInt(), 42);
0117         qDeleteAll(funcs);
0118     }
0119 };
0120 
0121 QTEST_MAIN(MetaFunctionTest)
0122 
0123 #include "metafunctiontest.moc"