File indexing completed on 2024-05-19 05:14:15
0001 /* 0002 SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org> 0003 SPDX-License-Identifier: LGPL-2.0-or-later 0004 */ 0005 0006 #include "kandroidextras/jnimethod.h" 0007 #include "kandroidextras/jnitypes.h" 0008 #include "kandroidextras/intent.h" 0009 #include "kandroidextras/javatypes.h" 0010 0011 #include <QtTest/qtest.h> 0012 0013 using namespace KAndroidExtras; 0014 0015 class TestClass 0016 { 0017 JNI_OBJECT(TestClass, android::content::Intent) 0018 public: 0019 TestClass() = default; 0020 JNI_CONSTRUCTOR(TestClass, android::content::Intent) 0021 JNI_METHOD(java::lang::String, getName) 0022 JNI_METHOD(void, setName, java::lang::String) 0023 JNI_METHOD(jint, getFlags) 0024 JNI_METHOD(void, setFlags, jint) 0025 JNI_METHOD(void, start) 0026 JNI_METHOD(bool, setCoordinates, jfloat, jfloat) 0027 JNI_METHOD(void, startIntent, android::content::Intent) 0028 JNI_METHOD(android::content::Intent, getIntent) 0029 JNI_METHOD(Jni::Array<java::lang::String>, getStringList) 0030 JNI_METHOD(Jni::Array<jshort>, getShortList) 0031 0032 // overloads 0033 JNI_METHOD(void, overloaded) 0034 JNI_METHOD(void, overloaded, jint) 0035 JNI_METHOD(void, overloaded, java::lang::String, bool) 0036 JNI_METHOD(jint, overloaded, jlong, java::lang::String, Jni::Array<jshort>) 0037 JNI_METHOD(Jni::Array<jshort>, overloaded, Intent) 0038 0039 JNI_PROPERTY(java::lang::String, name) 0040 0041 JNI_STATIC_METHOD(void, noRetNoArg) 0042 JNI_STATIC_METHOD(jlong, retNoArg) 0043 JNI_STATIC_METHOD(void, noRetArg, java::lang::String) 0044 JNI_STATIC_METHOD(android::content::Intent, retArg, bool) 0045 0046 // bool/jboolean arguments 0047 JNI_METHOD(void, setBool, bool) 0048 JNI_CONSTRUCTOR(TestClass, bool) 0049 0050 // basic C++ types that do not map to JNI (must not compile) 0051 // JNI_METHOD(void, setUnsigned, uint32_t) 0052 // JNI_STATIC_METHOD(void, setStaticUnsigned, uint64_t) 0053 // JNI_METHOD(char, charReturn) 0054 // JNI_STATIC_METHOD(uint64_t, staticCharReturn); 0055 // JNI_CONSTRUCTOR(TestClass, char) 0056 0057 friend class JniMethodTest; 0058 }; 0059 0060 class JniMethodTest : public QObject 0061 { 0062 Q_OBJECT 0063 private Q_SLOTS: 0064 void testMethodCalls() 0065 { 0066 #ifndef Q_OS_ANDROID 0067 TestClass obj; 0068 QString s = obj.getName(); 0069 Q_UNUSED(s); 0070 obj.setName(QStringLiteral("bla")); 0071 // explicit cast needed when coming from untyped JNI handler 0072 obj.setName(Jni::Object<java::lang::String>(QJniObject::fromString(QStringLiteral("bla")))); 0073 int i = obj.getFlags(); 0074 Q_UNUSED(i); 0075 obj.setFlags(42); 0076 obj.start(); 0077 bool b = obj.setCoordinates(0.0f, 0.0f); 0078 Q_UNUSED(b) 0079 0080 // implicit conversion 0081 b = obj.setCoordinates(0.0, 0.0); 0082 // implicit conversion, and must not copy the property wrapper 0083 obj.setName(obj.name); 0084 // implicit conversion from manual wrappers 0085 Intent intent; 0086 obj.startIntent(intent); 0087 // returning a non-wrapped type 0088 QJniObject j = obj.getIntent(); 0089 // lvalue QJniObject argument needs explicit cast 0090 obj.setName(Jni::Object<java::lang::String>(j)); 0091 // implicit conversion from a static property wrapper 0092 obj.setFlags(Intent::FLAG_GRANT_READ_URI_PERMISSION); 0093 0094 // avoiding type conversion on return values 0095 j = obj.getName(); 0096 // call chaining with JNI handle pass-through 0097 obj.setName(obj.getName()); 0098 0099 // conversion of array return types 0100 j = obj.getStringList(); 0101 QStringList l = obj.getStringList(); 0102 std::vector<QString> l2 = obj.getStringList(); 0103 std::vector<jshort> l3 = obj.getShortList(); 0104 0105 // nullptr arguments 0106 obj.startIntent(nullptr); 0107 0108 // overloaded methods 0109 obj.overloaded(); 0110 obj.overloaded(42); 0111 obj.overloaded(QStringLiteral("hello"), true); 0112 Jni::Array<jshort> l4 = obj.overloaded(intent); 0113 obj.overloaded(23, QStringLiteral("world"), l4); 0114 0115 // bool conversion 0116 obj.setBool(true); 0117 0118 QCOMPARE(obj.jniHandle().protocol().size(), 28); 0119 QCOMPARE(obj.jniHandle().protocol()[0], QLatin1StringView("callObjectMethod: getName ()Ljava/lang/String; ()")); 0120 QCOMPARE(obj.jniHandle().protocol()[1], QLatin1StringView("callMethod: setName (Ljava/lang/String;)V (o)")); 0121 QCOMPARE(obj.jniHandle().protocol()[2], QLatin1StringView("callMethod: setName (Ljava/lang/String;)V (o)")); 0122 QCOMPARE(obj.jniHandle().protocol()[3], QLatin1StringView("callMethod: getFlags ()I ()")); 0123 QCOMPARE(obj.jniHandle().protocol()[4], QLatin1StringView("callMethod: setFlags (I)V (I)")); 0124 QCOMPARE(obj.jniHandle().protocol()[5], QLatin1StringView("callMethod: start ()V ()")); 0125 QCOMPARE(obj.jniHandle().protocol()[6], QLatin1StringView("callMethod: setCoordinates (FF)Z (FF)")); 0126 0127 QCOMPARE(obj.jniHandle().protocol()[7], QLatin1StringView("callMethod: setCoordinates (FF)Z (FF)")); 0128 QCOMPARE(obj.jniHandle().protocol()[8], QLatin1StringView("getObjectField: name Ljava/lang/String;")); 0129 QCOMPARE(obj.jniHandle().protocol()[9], QLatin1StringView("callMethod: setName (Ljava/lang/String;)V (o)")); 0130 QCOMPARE(obj.jniHandle().protocol()[10], QLatin1StringView("callMethod: startIntent (Landroid/content/Intent;)V (o)")); 0131 QCOMPARE(obj.jniHandle().protocol()[11], QLatin1StringView("callObjectMethod: getIntent ()Landroid/content/Intent; ()")); 0132 QCOMPARE(obj.jniHandle().protocol()[12], QLatin1StringView("callMethod: setName (Ljava/lang/String;)V (o)")); 0133 QCOMPARE(obj.jniHandle().protocol()[13], QLatin1StringView("callMethod: setFlags (I)V (I)")); 0134 QCOMPARE(obj.jniHandle().protocol()[14], QLatin1StringView("callObjectMethod: getName ()Ljava/lang/String; ()")); 0135 QCOMPARE(obj.jniHandle().protocol()[15], QLatin1StringView("callObjectMethod: getName ()Ljava/lang/String; ()")); 0136 QCOMPARE(obj.jniHandle().protocol()[16], QLatin1StringView("callMethod: setName (Ljava/lang/String;)V (o)")); 0137 QCOMPARE(obj.jniHandle().protocol()[17], QLatin1StringView("callObjectMethod: getStringList ()[Ljava/lang/String; ()")); 0138 QCOMPARE(obj.jniHandle().protocol()[18], QLatin1StringView("callObjectMethod: getStringList ()[Ljava/lang/String; ()")); 0139 QCOMPARE(obj.jniHandle().protocol()[19], QLatin1StringView("callObjectMethod: getStringList ()[Ljava/lang/String; ()")); 0140 QCOMPARE(obj.jniHandle().protocol()[20], QLatin1StringView("callObjectMethod: getShortList ()[S ()")); 0141 QCOMPARE(obj.jniHandle().protocol()[21], QLatin1StringView("callMethod: startIntent (Landroid/content/Intent;)V (o)")); 0142 0143 QCOMPARE(obj.jniHandle().protocol()[22], QLatin1StringView("callMethod: overloaded ()V ()")); 0144 QCOMPARE(obj.jniHandle().protocol()[23], QLatin1StringView("callMethod: overloaded (I)V (I)")); 0145 QCOMPARE(obj.jniHandle().protocol()[24], QLatin1StringView("callMethod: overloaded (Ljava/lang/String;Z)V (oZ)")); 0146 QCOMPARE(obj.jniHandle().protocol()[25], QLatin1StringView("callObjectMethod: overloaded (Landroid/content/Intent;)[S (o)")); 0147 QCOMPARE(obj.jniHandle().protocol()[26], QLatin1StringView("callMethod: overloaded (JLjava/lang/String;[S)I (Joo)")); 0148 QCOMPARE(obj.jniHandle().protocol()[27], QLatin1StringView("callMethod: setBool (Z)V (Z)")); 0149 0150 // ctor call 0151 obj = TestClass(intent); 0152 QCOMPARE(obj.jniHandle().protocol().size(), 1); 0153 QCOMPARE(obj.jniHandle().protocol()[0], QLatin1StringView("ctor: android/content/Intent (Landroid/content/Intent;)V (o)")); 0154 obj = TestClass(false); 0155 QCOMPARE(obj.jniHandle().protocol().size(), 1); 0156 QCOMPARE(obj.jniHandle().protocol()[0], QLatin1StringView("ctor: android/content/Intent (Z)V (Z)")); 0157 #if 0 0158 // stuff that must not compile 0159 obj.setName(42); 0160 obj.setFlags(QStringLiteral("42")); 0161 s = obj.getStringList(); 0162 obj.setFlags(nullptr); 0163 #endif 0164 #endif 0165 } 0166 0167 void testStaticCalls() 0168 { 0169 #ifndef Q_OS_ANDROID 0170 QJniObject::m_staticProtocol.clear(); 0171 0172 TestClass::noRetNoArg(); 0173 TestClass::noRetArg(QStringLiteral("test")); 0174 TestClass::retNoArg(); 0175 QJniObject o = TestClass::retArg(true); 0176 0177 QCOMPARE(QJniObject::m_staticProtocol.size(), 3); 0178 QCOMPARE(QJniObject::m_staticProtocol[0], QLatin1StringView("callStaticMethod: android/content/Intent noRetNoArg ()V ()")); 0179 QCOMPARE(QJniObject::m_staticProtocol[1], QLatin1StringView("callStaticMethod: android/content/Intent noRetArg (Ljava/lang/String;)V (o)")); 0180 QCOMPARE(QJniObject::m_staticProtocol[2], QLatin1StringView("callStaticMethod: android/content/Intent retNoArg ()J ()")); 0181 QCOMPARE(o.protocol().at(0), QLatin1StringView("callStaticObjectMethod: android/content/Intent retArg (Z)Landroid/content/Intent; (Z)")); 0182 #endif 0183 } 0184 }; 0185 0186 QTEST_GUILESS_MAIN(JniMethodTest) 0187 0188 #include "jnimethodtest.moc"