File indexing completed on 2025-02-02 05:02:41

0001 /*
0002     SPDX-FileCopyrightText: 2020-2022 Volker Krause <vkrause@kde.org>
0003     SPDX-License-Identifier: LGPL-2.0-or-later
0004 */
0005 
0006 #ifndef KANDROIDEXTRAS_MOCK_JNIOBJECT_H
0007 #define KANDROIDEXTRAS_MOCK_JNIOBJECT_H
0008 
0009 #include "kandroidextras_export.h"
0010 #include "jni.h"
0011 
0012 #include "kandroidextras/jnisignature.h"
0013 #include "kandroidextras/jnitypes.h"
0014 
0015 #include <QExplicitlySharedDataPointer>
0016 #include <QStringList>
0017 #include <QVariant>
0018 
0019 class MockJniObjectBasePrivate;
0020 
0021 namespace KAndroidExtras {
0022 namespace Internal {
0023 template <typename T>
0024 constexpr inline const char* argTypeToString()
0025 {
0026     return KAndroidExtras::Jni::signature<T>();
0027 }
0028 template <>
0029 constexpr inline const char* argTypeToString<jobject>()
0030 {
0031     return "o";
0032 }
0033 
0034 class KANDROIDEXTRAS_EXPORT MockJniObjectBase {
0035 public:
0036     MockJniObjectBase();
0037     MockJniObjectBase(const MockJniObjectBase&);
0038     ~MockJniObjectBase();
0039     MockJniObjectBase& operator=(const MockJniObjectBase&);
0040 
0041     MockJniObjectBase(const char *className);
0042 
0043     inline MockJniObjectBase(const char *className, const char *signature)
0044         : MockJniObjectBase()
0045     {
0046         addToProtocol(QLatin1StringView("ctor: ") + QLatin1StringView(className) + QLatin1Char(' ') + QLatin1StringView(signature));
0047     }
0048     template <typename ...Args>
0049     inline MockJniObjectBase(const char *className, const char *signature, Args...)
0050         : MockJniObjectBase()
0051     {
0052         addToProtocol(QLatin1StringView("ctor: ") + QLatin1StringView(className) + QLatin1Char(' ') + QLatin1StringView(signature)
0053             + QLatin1StringView(" (") + (...+QLatin1StringView(KAndroidExtras::Internal::argTypeToString<Args>())) + QLatin1Char(')'));
0054     }
0055 
0056     MockJniObjectBase(jobject object);
0057 
0058     bool isValid() const { return true; }
0059 
0060     static QStringList m_staticProtocol;
0061 
0062     QStringList protocol() const;
0063     void addToProtocol(const QString &line) const;
0064 
0065 protected:
0066     QVariant property(const QByteArray &name) const;
0067     void setProperty(const QByteArray &name, const QVariant &value);
0068     QVariant value() const;
0069     void setValue(const QVariant &value);
0070     void setData(jobject object);
0071 
0072     void setProtocol(const QStringList &protocol);
0073     QExplicitlySharedDataPointer<MockJniObjectBasePrivate> d;
0074 };
0075 
0076 
0077 template <typename JniObjectT>
0078 class MockJniObject : public MockJniObjectBase {
0079 public:
0080     using MockJniObjectBase::MockJniObjectBase;
0081     static inline JniObjectT fromString(const QString &s)
0082     {
0083         JniObjectT o;
0084         o.setValue(s);
0085         return o;
0086     }
0087     static inline JniObjectT fromLocalRef(jobject o)
0088     {
0089         JniObjectT obj;
0090         obj.addToProtocol(QLatin1StringView("ctor: ") + QString::number((qulonglong)o));
0091         return obj;
0092     }
0093     inline QString toString() const
0094     {
0095         return value().userType() == QMetaType::QString ? value().toString() : protocol().join(QLatin1Char('\n'));
0096     }
0097 
0098     inline jobject object() const { return d.data(); }
0099     template <typename T>
0100     inline T object() const { return {}; }
0101 
0102     template <typename T, typename ...Args>
0103     inline T callMethod(const char *methodName, const char *signature, Args...) const
0104     {
0105         const QString s = QLatin1StringView("callMethod: ") + QLatin1StringView(methodName) + QLatin1Char(' ') + QLatin1StringView(signature) + QLatin1StringView(" (")
0106             + (...+QLatin1StringView(KAndroidExtras::Internal::argTypeToString<Args>())) + QLatin1Char(')');
0107         addToProtocol(s);
0108         if constexpr (!std::is_same_v<T, void>) {
0109             return {};
0110         }
0111     }
0112     template <typename T>
0113     inline T callMethod(const char *methodName, const char *signature) const
0114     {
0115         const QString s = QLatin1StringView("callMethod: ") + QLatin1StringView(methodName) + QLatin1Char(' ') + QLatin1StringView(signature) + QLatin1StringView(" ()");
0116         addToProtocol(s);
0117         if constexpr (!std::is_same_v<T, void>) {
0118             return {};
0119         }
0120     }
0121 
0122     template <typename ...Args>
0123     inline JniObjectT callObjectMethod(const char *methodName, const char *signature, Args...) const
0124     {
0125         const QString s = QLatin1StringView("callObjectMethod: ") + QLatin1StringView(methodName) + QLatin1Char(' ') + QLatin1StringView(signature) + QLatin1StringView(" (")
0126             + (...+QLatin1StringView(KAndroidExtras::Internal::argTypeToString<Args>())) + QLatin1Char(')');
0127         addToProtocol(s);
0128 
0129         JniObjectT obj;
0130         obj.setProtocol(protocol());
0131         return obj;
0132     }
0133     inline JniObjectT callObjectMethod(const char *methodName, const char *signature) const
0134     {
0135         addToProtocol(QLatin1StringView("callObjectMethod: ") + QLatin1StringView(methodName) + QLatin1Char(' ') + QLatin1StringView(signature) + QLatin1StringView(" ()"));
0136 
0137         JniObjectT obj;
0138         obj.setProtocol(protocol());
0139         return obj;
0140     }
0141 
0142     template <typename T>
0143     inline T getField(const char *fieldName) const
0144     {
0145         addToProtocol(QLatin1StringView("getField: ") + QLatin1StringView(fieldName) + QLatin1Char(' ') + QLatin1StringView(KAndroidExtras::Jni::signature<T>()));
0146         return property(fieldName).template value<T>();
0147     }
0148 
0149     inline JniObjectT getObjectField(const char *fieldName, const char *signature) const
0150     {
0151         addToProtocol(QLatin1StringView("getObjectField: ") + QLatin1StringView(fieldName) + QLatin1Char(' ') + QLatin1StringView(signature));
0152         return property(fieldName).template value<JniObjectT>();
0153     }
0154 
0155     template <typename T>
0156     inline void setField(const char *fieldName, const char *signature, T value)
0157     {
0158         Q_UNUSED(value);
0159         addToProtocol(QLatin1StringView("setField: ") + QLatin1StringView(fieldName) + QLatin1Char(' ') + QLatin1StringView(signature));
0160         if constexpr (std::is_same_v<jobject, T>) {
0161             setObjectProperty(fieldName, value);
0162         } else {
0163             setProperty(fieldName, QVariant::fromValue(value));
0164         }
0165     }
0166     template <typename T>
0167     inline void setField(const char *fieldName, T value)
0168     {
0169         setField(fieldName, KAndroidExtras::Jni::signature<T>(), value);
0170     }
0171 
0172     template <typename T, typename ...Args>
0173     static inline T callStaticMethod(const char *className, const char *methodName, const char *signature, Args...)
0174     {
0175         const QString s = QLatin1StringView("callStaticMethod: ") + QLatin1StringView(className) + QLatin1Char(' ')
0176             + QLatin1StringView(methodName) + QLatin1Char(' ') + QLatin1StringView(signature) + QLatin1StringView(" (")
0177             + (...+QLatin1StringView(KAndroidExtras::Internal::argTypeToString<Args>())) + QLatin1Char(')');
0178         m_staticProtocol.push_back(s);
0179         if constexpr (!std::is_same_v<T, void>) {
0180             return {};
0181         }
0182     }
0183     template <typename T>
0184     static inline T callStaticMethod(const char *className, const char *methodName, const char *signature)
0185     {
0186         const QString s = QLatin1StringView("callStaticMethod: ") + QLatin1StringView(className) + QLatin1Char(' ')
0187             + QLatin1StringView(methodName) + QLatin1Char(' ') + QLatin1StringView(signature) + QLatin1StringView(" ()");
0188         m_staticProtocol.push_back(s);
0189         if constexpr (!std::is_same_v<T, void>) {
0190             return {};
0191         }
0192     }
0193 
0194     template <typename ...Args>
0195     static inline JniObjectT callStaticObjectMethod(const char *className, const char *methodName, const char *signature, Args...)
0196     {
0197         const QString s = QLatin1StringView("callStaticObjectMethod: ") + QLatin1StringView(className) + QLatin1Char(' ')
0198             + QLatin1StringView(methodName) + QLatin1Char(' ') + QLatin1StringView(signature) + QLatin1StringView(" (")
0199             + (...+QLatin1StringView(KAndroidExtras::Internal::argTypeToString<Args>())) + QLatin1Char(')');
0200         JniObjectT obj;
0201         obj.addToProtocol(s);
0202         return obj;
0203     }
0204 
0205     static inline JniObjectT callStaticObjectMethod(const char *className, const char *methodName, const char *signature)
0206     {
0207         JniObjectT obj;
0208         obj.addToProtocol(QLatin1StringView("callStaticObjectMethod: ") + QLatin1StringView(className) + QLatin1Char(' ')
0209             + QLatin1StringView(methodName) + QLatin1Char(' ') + QLatin1StringView(signature) + QLatin1StringView(" ()"));
0210         return obj;
0211     }
0212 
0213     static inline JniObjectT getStaticObjectField(const char *className, const char *fieldName, const char *signature)
0214     {
0215         m_staticProtocol.push_back(QLatin1StringView("getStaticObjectField: ") + QLatin1StringView(className) + QLatin1Char(' ') + QLatin1StringView(fieldName) + QLatin1Char(' ') + QLatin1StringView(signature));
0216         return {};
0217     }
0218 
0219     template <typename T>
0220     static inline JniObjectT getStaticObjectField(const char *className, const char *fieldName)
0221     {
0222         m_staticProtocol.push_back(QLatin1StringView("getStaticObjectField<>: ") + QLatin1StringView(className) + QLatin1Char(' ') + QLatin1StringView(fieldName));
0223         return {};
0224     }
0225 
0226     template <typename T>
0227     static inline T getStaticField(const char *className, const char *fieldName)
0228     {
0229         m_staticProtocol.push_back(QLatin1StringView("getStaticField<>: ") + QLatin1StringView(className) + QLatin1Char(' ') + QLatin1StringView(fieldName) + QLatin1Char(' ') + QLatin1StringView(KAndroidExtras::Jni::signature<T>()));
0230         return {};
0231     }
0232 
0233     inline void setObjectProperty(const QByteArray &name, jobject value)
0234     {
0235         JniObjectT o;
0236         o.setData(value);
0237         setProperty(name, QVariant::fromValue(o));
0238     }
0239 };
0240 
0241 }
0242 }
0243 
0244 #endif