summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp')
-rw-r--r--tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp229
1 files changed, 190 insertions, 39 deletions
diff --git a/tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp b/tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp
index 093c387dcc..bf582041f3 100644
--- a/tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp
+++ b/tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp
@@ -1,9 +1,12 @@
// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest>
#include <QtCore/qjnitypes.h>
+#include <QtCore/qjniarray.h>
+
+using namespace Qt::StringLiterals;
class tst_QJniTypes : public QObject
{
@@ -12,44 +15,62 @@ class tst_QJniTypes : public QObject
public:
tst_QJniTypes() = default;
+ static void nativeClassMethod(JNIEnv *, jclass, int);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(nativeClassMethod);
+
private slots:
void initTestCase();
void nativeMethod();
+ void construct();
+ void stringTypeCantBeArgument();
};
struct QtJavaWrapper {};
template<>
-constexpr auto QtJniTypes::typeSignature<QtJavaWrapper>()
+struct QtJniTypes::Traits<QtJavaWrapper>
{
- return QtJniTypes::String("Lorg/qtproject/qt/android/QtJavaWrapper;");
-}
+ static constexpr auto signature()
+ {
+ return QtJniTypes::CTString("Lorg/qtproject/qt/android/QtJavaWrapper;");
+ }
+};
template<>
-constexpr auto QtJniTypes::typeSignature<QJniObject>()
+struct QtJniTypes::Traits<QJniObject>
{
- return QtJniTypes::String("Ljava/lang/Object;");
-}
+ static constexpr auto signature()
+ {
+ return QtJniTypes::CTString("Ljava/lang/Object;");
+ }
+};
struct QtCustomJniObject : QJniObject {};
+
template<>
-constexpr auto QtJniTypes::typeSignature<QtCustomJniObject>()
+struct QtJniTypes::Traits<QtCustomJniObject>
{
- return QtJniTypes::String("Lorg/qtproject/qt/android/QtCustomJniObject;");
-}
+ static constexpr auto signature()
+ {
+ return QtJniTypes::CTString("Lorg/qtproject/qt/android/QtCustomJniObject;");
+ }
+};
-static_assert(QtJniTypes::typeSignature<QtJavaWrapper>() == "Lorg/qtproject/qt/android/QtJavaWrapper;");
-static_assert(QtJniTypes::typeSignature<QtJavaWrapper>() != "Ljava/lang/Object;");
-static_assert(!(QtJniTypes::typeSignature<QtJavaWrapper>() == "X"));
+static_assert(QtJniTypes::Traits<QtJavaWrapper>::signature() == "Lorg/qtproject/qt/android/QtJavaWrapper;");
+static_assert(QtJniTypes::Traits<QtJavaWrapper>::signature() != "Ljava/lang/Object;");
+static_assert(!(QtJniTypes::Traits<QtJavaWrapper>::signature() == "X"));
-Q_DECLARE_JNI_TYPE(JavaType, "Lorg/qtproject/qt/JavaType;");
-static_assert(QtJniTypes::typeSignature<QtJniTypes::JavaType>() == "Lorg/qtproject/qt/JavaType;");
-Q_DECLARE_JNI_TYPE(ArrayType, "[Lorg/qtproject/qt/ArrayType;")
-static_assert(QtJniTypes::typeSignature<QtJniTypes::ArrayType>() == "[Lorg/qtproject/qt/ArrayType;");
+Q_DECLARE_JNI_CLASS(JavaType, "org/qtproject/qt/JavaType");
+static_assert(QtJniTypes::Traits<QtJniTypes::JavaType>::signature() == "Lorg/qtproject/qt/JavaType;");
+static_assert(QtJniTypes::Traits<QtJniTypes::JavaType[]>::signature() == "[Lorg/qtproject/qt/JavaType;");
-static_assert(QtJniTypes::className<jstring>() == "java/lang/String");
+Q_DECLARE_JNI_CLASS(String, "java/lang/String");
+static_assert(QtJniTypes::Traits<jstring>::className() == "java/lang/String");
+static_assert(QtJniTypes::Traits<QtJniTypes::String>::className() == "java/lang/String");
+static_assert(QtJniTypes::Traits<QtJniTypes::String>::signature() == "Ljava/lang/String;");
+static_assert(QtJniTypes::Traits<QtJniTypes::String[]>::signature() == "[Ljava/lang/String;");
Q_DECLARE_JNI_CLASS(QtTextToSpeech, "org/qtproject/qt/android/speech/QtTextToSpeech")
-static_assert(QtJniTypes::className<QtJniTypes::QtTextToSpeech>() == "org/qtproject/qt/android/speech/QtTextToSpeech");
+static_assert(QtJniTypes::Traits<QtJniTypes::QtTextToSpeech>::className() == "org/qtproject/qt/android/speech/QtTextToSpeech");
static_assert(QtJniTypes::fieldSignature<jint>() == "I");
static_assert(QtJniTypes::fieldSignature<jint[]>() == "[I");
@@ -91,28 +112,49 @@ static_assert(QtJniTypes::isArrayType<jobject[]>());
static_assert(QtJniTypes::isArrayType<jobjectArray>());
static_assert(QtJniTypes::isArrayType<QtJavaWrapper[]>());
-static_assert(QtJniTypes::String("ABCDE").startsWith("ABC"));
-static_assert(QtJniTypes::String("ABCDE").startsWith("A"));
-static_assert(QtJniTypes::String("ABCDE").startsWith("ABCDE"));
-static_assert(!QtJniTypes::String("ABCDE").startsWith("ABCDEF"));
-static_assert(!QtJniTypes::String("ABCDE").startsWith("9AB"));
-static_assert(QtJniTypes::String("ABCDE").startsWith('A'));
-static_assert(!QtJniTypes::String("ABCDE").startsWith('B'));
-
-static_assert(QtJniTypes::String("ABCDE").endsWith("CDE"));
-static_assert(QtJniTypes::String("ABCDE").endsWith("E"));
-static_assert(QtJniTypes::String("ABCDE").endsWith("ABCDE"));
-static_assert(!QtJniTypes::String("ABCDE").endsWith("DEF"));
-static_assert(!QtJniTypes::String("ABCDE").endsWith("ABCDEF"));
-static_assert(QtJniTypes::String("ABCDE").endsWith('E'));
-static_assert(!QtJniTypes::String("ABCDE").endsWith('F'));
+static_assert(QtJniTypes::CTString("ABCDE").startsWith("ABC"));
+static_assert(QtJniTypes::CTString("ABCDE").startsWith("A"));
+static_assert(QtJniTypes::CTString("ABCDE").startsWith("ABCDE"));
+static_assert(!QtJniTypes::CTString("ABCDE").startsWith("ABCDEF"));
+static_assert(!QtJniTypes::CTString("ABCDE").startsWith("9AB"));
+static_assert(QtJniTypes::CTString("ABCDE").startsWith('A'));
+static_assert(!QtJniTypes::CTString("ABCDE").startsWith('B'));
+
+static_assert(QtJniTypes::Traits<QJniArray<jobject>>::signature() == "[Ljava/lang/Object;");
+static_assert(QtJniTypes::Traits<QJniArray<jbyte>>::signature() == "[B");
+static_assert(QtJniTypes::isObjectType<QJniArray<jbyte>>());
+
+static_assert(QtJniTypes::CTString("ABCDE").endsWith("CDE"));
+static_assert(QtJniTypes::CTString("ABCDE").endsWith("E"));
+static_assert(QtJniTypes::CTString("ABCDE").endsWith("ABCDE"));
+static_assert(!QtJniTypes::CTString("ABCDE").endsWith("DEF"));
+static_assert(!QtJniTypes::CTString("ABCDE").endsWith("ABCDEF"));
+static_assert(QtJniTypes::CTString("ABCDE").endsWith('E'));
+static_assert(!QtJniTypes::CTString("ABCDE").endsWith('F'));
+
+enum UnscopedEnum {};
+enum class ScopedEnum {};
+enum class IntEnum : int {};
+enum class UnsignedEnum : unsigned {};
+enum class Int8Enum : int8_t {};
+enum class ShortEnum : short {};
+enum class LongEnum : quint64 {};
+enum class JIntEnum : jint {};
+
+static_assert(QtJniTypes::Traits<UnscopedEnum>::signature() == "I");
+static_assert(QtJniTypes::Traits<ScopedEnum>::signature() == "I");
+static_assert(QtJniTypes::Traits<IntEnum>::signature() == "I");
+static_assert(QtJniTypes::Traits<UnsignedEnum>::signature() == "I");
+static_assert(QtJniTypes::Traits<Int8Enum>::signature() == "B");
+static_assert(QtJniTypes::Traits<LongEnum>::signature() == "J");
+static_assert(QtJniTypes::Traits<JIntEnum>::signature() == "I");
void tst_QJniTypes::initTestCase()
{
}
-static bool nativeFunction(JNIEnv *, jclass, int, jstring, long)
+static bool nativeFunction(JNIEnv *, jclass, int, jstring, quint64)
{
return true;
}
@@ -120,12 +162,121 @@ Q_DECLARE_JNI_NATIVE_METHOD(nativeFunction)
static_assert(QtJniTypes::nativeMethodSignature(nativeFunction) == "(ILjava/lang/String;J)Z");
+static QString nativeFunctionStrings(JNIEnv *, jclass, const QString &, const QtJniTypes::String &)
+{
+ return QString();
+}
+Q_DECLARE_JNI_NATIVE_METHOD(nativeFunctionStrings)
+
+static_assert(QtJniTypes::nativeMethodSignature(nativeFunctionStrings)
+ == "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
+
+static int forwardDeclaredNativeFunction(JNIEnv *, jobject, bool);
+Q_DECLARE_JNI_NATIVE_METHOD(forwardDeclaredNativeFunction)
+static int forwardDeclaredNativeFunction(JNIEnv *, jobject, bool) { return 0; }
+static_assert(QtJniTypes::nativeMethodSignature(forwardDeclaredNativeFunction) == "(Z)I");
+
+static_assert(QtJniTypes::nativeMethodSignature(tst_QJniTypes::nativeClassMethod) == "(I)V");
+void tst_QJniTypes::nativeClassMethod(JNIEnv *, jclass, int) {}
+
void tst_QJniTypes::nativeMethod()
{
- const auto method = Q_JNI_NATIVE_METHOD(nativeFunction);
- QVERIFY(method.fnPtr == nativeFunction);
- QCOMPARE(method.name, "nativeFunction");
- QCOMPARE(method.signature, "(ILjava/lang/String;J)Z");
+ {
+ const auto method = Q_JNI_NATIVE_METHOD(nativeFunction);
+ QVERIFY(method.fnPtr == QtJniMethods::va_nativeFunction);
+ QCOMPARE(method.name, "nativeFunction");
+ QCOMPARE(method.signature, "(ILjava/lang/String;J)Z");
+ }
+
+ {
+ const auto method = Q_JNI_NATIVE_METHOD(forwardDeclaredNativeFunction);
+ QVERIFY(method.fnPtr == QtJniMethods::va_forwardDeclaredNativeFunction);
+ }
+
+ {
+ const auto method = Q_JNI_NATIVE_SCOPED_METHOD(nativeClassMethod, tst_QJniTypes);
+ QVERIFY(method.fnPtr == va_nativeClassMethod);
+ }
+}
+
+void tst_QJniTypes::construct()
+{
+ using namespace QtJniTypes;
+
+ const QString text = u"Java String"_s;
+ String str(text);
+ QVERIFY(str.isValid());
+ QCOMPARE(str.toString(), text);
+
+ jobject jref = nullptr; // must be jobject, not jstring
+ {
+ // if jref would be a jstring, then this would call the
+ // Java String copy constructor!
+ String jstr(jref);
+ QVERIFY(!jstr.isValid());
+ }
+ jref = str.object<jstring>();
+ {
+ String jstr(jref);
+ QVERIFY(jstr.isValid());
+ QCOMPARE(jstr.toString(), text);
+ }
+
+ String str2 = str;
+ QCOMPARE(str.toString(), text);
+ String str3 = std::move(str2);
+ QCOMPARE(str3.toString(), text);
+}
+
+template <typename ...Arg>
+static constexpr bool isValidArgument(Arg &&...) noexcept
+{
+ return QtJniTypes::ValidSignatureTypesDetail<q20::remove_cvref_t<Arg>...>;
+}
+
+enum class Overload
+{
+ ClassNameAndMethod,
+ OnlyMethod,
+};
+
+template <typename Ret, typename ...Args
+#ifndef Q_QDOC
+ , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true
+#endif
+>
+static constexpr auto callStaticMethod(const char *className, const char *methodName, Args &&...)
+{
+ Q_UNUSED(className);
+ Q_UNUSED(methodName);
+ return Overload::ClassNameAndMethod;
+}
+
+template <typename Klass, typename Ret, typename ...Args
+#ifndef Q_QDOC
+ , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true
+#endif
+>
+static constexpr auto callStaticMethod(const char *methodName, Args &&...)
+{
+ Q_UNUSED(methodName);
+ return Overload::OnlyMethod;
+}
+
+void tst_QJniTypes::stringTypeCantBeArgument()
+{
+ const char *methodName = "staticEchoMethod";
+
+ static_assert(!isValidArgument(QtJniTypes::Traits<QtJniTypes::JavaType>::className()));
+ static_assert(!isValidArgument("someFunctionName"));
+ static_assert(!isValidArgument(methodName));
+ static_assert(!isValidArgument(QtJniTypes::Traits<QtJniTypes::JavaType>::className(),
+ "someFunctionName", methodName, 42));
+
+ static_assert(callStaticMethod<jstring, jint>("class name", "method name", 42)
+ == Overload::ClassNameAndMethod);
+ static_assert(callStaticMethod<QtJniTypes::JavaType, jint>("method name", 42)
+ == Overload::OnlyMethod);
}
QTEST_MAIN(tst_QJniTypes)