/* SPDX-FileCopyrightText: 2020-2022 Volker Krause SPDX-License-Identifier: LGPL-2.0-or-later */ #ifndef KANDROIDEXTRAS_MOCK_JNIOBJECT_H #define KANDROIDEXTRAS_MOCK_JNIOBJECT_H #include "jni.h" #include "kandroidextras_export.h" #include "kandroidextras/jnisignature.h" #include "kandroidextras/jnitypes.h" #include #include #include class MockJniObjectBasePrivate; namespace KAndroidExtras { namespace Internal { template constexpr inline const char *argTypeToString() { return KAndroidExtras::Jni::signature(); } template<> constexpr inline const char *argTypeToString() { return "o"; } class KANDROIDEXTRAS_EXPORT MockJniObjectBase { public: MockJniObjectBase(); MockJniObjectBase(const MockJniObjectBase &); ~MockJniObjectBase(); MockJniObjectBase &operator=(const MockJniObjectBase &); MockJniObjectBase(const char *className); inline MockJniObjectBase(const char *className, const char *signature) : MockJniObjectBase() { addToProtocol(QLatin1StringView("ctor: ") + QLatin1StringView(className) + QLatin1Char(' ') + QLatin1StringView(signature)); } template inline MockJniObjectBase(const char *className, const char *signature, Args...) : MockJniObjectBase() { addToProtocol(QLatin1StringView("ctor: ") + QLatin1StringView(className) + QLatin1Char(' ') + QLatin1StringView(signature) + QLatin1StringView(" (") + (... + QLatin1StringView(KAndroidExtras::Internal::argTypeToString())) + QLatin1Char(')')); } MockJniObjectBase(jobject object); bool isValid() const { return true; } static QStringList m_staticProtocol; QStringList protocol() const; void addToProtocol(const QString &line) const; protected: QVariant property(const QByteArray &name) const; void setProperty(const QByteArray &name, const QVariant &value); QVariant value() const; void setValue(const QVariant &value); void setData(jobject object); void setProtocol(const QStringList &protocol); QExplicitlySharedDataPointer d; }; template class MockJniObject : public MockJniObjectBase { public: using MockJniObjectBase::MockJniObjectBase; static inline JniObjectT fromString(const QString &s) { JniObjectT o; o.setValue(s); return o; } static inline JniObjectT fromLocalRef(jobject o) { JniObjectT obj; obj.addToProtocol(QLatin1StringView("ctor: ") + QString::number((qulonglong)o)); return obj; } inline QString toString() const { return value().userType() == QMetaType::QString ? value().toString() : protocol().join(QLatin1Char('\n')); } inline jobject object() const { return d.data(); } template inline T object() const { return {}; } template inline T callMethod(const char *methodName, const char *signature, Args...) const { const QString s = QLatin1StringView("callMethod: ") + QLatin1StringView(methodName) + QLatin1Char(' ') + QLatin1StringView(signature) + QLatin1StringView(" (") + (... + QLatin1StringView(KAndroidExtras::Internal::argTypeToString())) + QLatin1Char(')'); addToProtocol(s); if constexpr (!std::is_same_v) { return {}; } } template inline T callMethod(const char *methodName, const char *signature) const { const QString s = QLatin1StringView("callMethod: ") + QLatin1StringView(methodName) + QLatin1Char(' ') + QLatin1StringView(signature) + QLatin1StringView(" ()"); addToProtocol(s); if constexpr (!std::is_same_v) { return {}; } } template inline JniObjectT callObjectMethod(const char *methodName, const char *signature, Args...) const { const QString s = QLatin1StringView("callObjectMethod: ") + QLatin1StringView(methodName) + QLatin1Char(' ') + QLatin1StringView(signature) + QLatin1StringView(" (") + (... + QLatin1StringView(KAndroidExtras::Internal::argTypeToString())) + QLatin1Char(')'); addToProtocol(s); JniObjectT obj; obj.setProtocol(protocol()); return obj; } inline JniObjectT callObjectMethod(const char *methodName, const char *signature) const { addToProtocol(QLatin1StringView("callObjectMethod: ") + QLatin1StringView(methodName) + QLatin1Char(' ') + QLatin1StringView(signature) + QLatin1StringView(" ()")); JniObjectT obj; obj.setProtocol(protocol()); return obj; } template inline T getField(const char *fieldName) const { addToProtocol(QLatin1StringView("getField: ") + QLatin1StringView(fieldName) + QLatin1Char(' ') + QLatin1StringView(KAndroidExtras::Jni::signature())); return property(fieldName).template value(); } inline JniObjectT getObjectField(const char *fieldName, const char *signature) const { addToProtocol(QLatin1StringView("getObjectField: ") + QLatin1StringView(fieldName) + QLatin1Char(' ') + QLatin1StringView(signature)); return property(fieldName).template value(); } template inline void setField(const char *fieldName, const char *signature, T value) { Q_UNUSED(value); addToProtocol(QLatin1StringView("setField: ") + QLatin1StringView(fieldName) + QLatin1Char(' ') + QLatin1StringView(signature)); if constexpr (std::is_same_v) { setObjectProperty(fieldName, value); } else { setProperty(fieldName, QVariant::fromValue(value)); } } template inline void setField(const char *fieldName, T value) { setField(fieldName, KAndroidExtras::Jni::signature(), value); } template static inline T callStaticMethod(const char *className, const char *methodName, const char *signature, Args...) { const QString s = QLatin1StringView("callStaticMethod: ") + QLatin1StringView(className) + QLatin1Char(' ') + QLatin1StringView(methodName) + QLatin1Char(' ') + QLatin1StringView(signature) + QLatin1StringView(" (") + (... + QLatin1StringView(KAndroidExtras::Internal::argTypeToString())) + QLatin1Char(')'); m_staticProtocol.push_back(s); if constexpr (!std::is_same_v) { return {}; } } template static inline T callStaticMethod(const char *className, const char *methodName, const char *signature) { const QString s = QLatin1StringView("callStaticMethod: ") + QLatin1StringView(className) + QLatin1Char(' ') + QLatin1StringView(methodName) + QLatin1Char(' ') + QLatin1StringView(signature) + QLatin1StringView(" ()"); m_staticProtocol.push_back(s); if constexpr (!std::is_same_v) { return {}; } } template static inline JniObjectT callStaticObjectMethod(const char *className, const char *methodName, const char *signature, Args...) { const QString s = QLatin1StringView("callStaticObjectMethod: ") + QLatin1StringView(className) + QLatin1Char(' ') + QLatin1StringView(methodName) + QLatin1Char(' ') + QLatin1StringView(signature) + QLatin1StringView(" (") + (... + QLatin1StringView(KAndroidExtras::Internal::argTypeToString())) + QLatin1Char(')'); JniObjectT obj; obj.addToProtocol(s); return obj; } static inline JniObjectT callStaticObjectMethod(const char *className, const char *methodName, const char *signature) { JniObjectT obj; obj.addToProtocol(QLatin1StringView("callStaticObjectMethod: ") + QLatin1StringView(className) + QLatin1Char(' ') + QLatin1StringView(methodName) + QLatin1Char(' ') + QLatin1StringView(signature) + QLatin1StringView(" ()")); return obj; } static inline JniObjectT getStaticObjectField(const char *className, const char *fieldName, const char *signature) { m_staticProtocol.push_back(QLatin1StringView("getStaticObjectField: ") + QLatin1StringView(className) + QLatin1Char(' ') + QLatin1StringView(fieldName) + QLatin1Char(' ') + QLatin1StringView(signature)); return {}; } template static inline JniObjectT getStaticObjectField(const char *className, const char *fieldName) { m_staticProtocol.push_back(QLatin1StringView("getStaticObjectField<>: ") + QLatin1StringView(className) + QLatin1Char(' ') + QLatin1StringView(fieldName)); return {}; } template static inline T getStaticField(const char *className, const char *fieldName) { m_staticProtocol.push_back(QLatin1StringView("getStaticField<>: ") + QLatin1StringView(className) + QLatin1Char(' ') + QLatin1StringView(fieldName) + QLatin1Char(' ') + QLatin1StringView(KAndroidExtras::Jni::signature())); return {}; } inline void setObjectProperty(const QByteArray &name, jobject value) { JniObjectT o; o.setData(value); setProperty(name, QVariant::fromValue(o)); } }; } } #endif