diff options
Diffstat (limited to 'tests/auto/corelib/kernel/qjnienvironment')
3 files changed, 173 insertions, 70 deletions
diff --git a/tests/auto/corelib/kernel/qjnienvironment/CMakeLists.txt b/tests/auto/corelib/kernel/qjnienvironment/CMakeLists.txt index 25e7e51ba6..f405438314 100644 --- a/tests/auto/corelib/kernel/qjnienvironment/CMakeLists.txt +++ b/tests/auto/corelib/kernel/qjnienvironment/CMakeLists.txt @@ -1,7 +1,16 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + ##################################################################### ## tst_qjnienvironment Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qjnienvironment LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + qt_internal_add_test(tst_qjnienvironment SOURCES tst_qjnienvironment.cpp @@ -11,6 +20,4 @@ if(ANDROID) set_property(TARGET tst_qjnienvironment APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/testdata ) - # QTBUG-88840 - qt_android_generate_deployment_settings(tst_qjnienvironment) endif() diff --git a/tests/auto/corelib/kernel/qjnienvironment/testdata/src/org/qtproject/qt/android/testdata/QtJniEnvironmentTestClass.java b/tests/auto/corelib/kernel/qjnienvironment/testdata/src/org/qtproject/qt/android/testdata/QtJniEnvironmentTestClass.java index 411bd1501d..4f307b3bc7 100644 --- a/tests/auto/corelib/kernel/qjnienvironment/testdata/src/org/qtproject/qt/android/testdata/QtJniEnvironmentTestClass.java +++ b/tests/auto/corelib/kernel/qjnienvironment/testdata/src/org/qtproject/qt/android/testdata/QtJniEnvironmentTestClass.java @@ -1,36 +1,15 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only package org.qtproject.qt.android.testdatapackage; public class QtJniEnvironmentTestClass { private static native void callbackFromJava(String message); + private static native void namedCallbackFromJava(String message); + private static native void memberCallbackFromJava(String message); + private static native void namedMemberCallbackFromJava(String message); + private static native void namespaceCallbackFromJava(String message); private static native void intCallbackFromJava(int value); public final int INT_FIELD = 123; @@ -43,6 +22,26 @@ public class QtJniEnvironmentTestClass callbackFromJava("From Java: " + message); } + public static void namedAppendJavaToString(String message) + { + namedCallbackFromJava("From Java (named): " + message); + } + + public static void memberAppendJavaToString(String message) + { + memberCallbackFromJava("From Java (member): " + message); + } + + public static void namedMemberAppendJavaToString(String message) + { + namedMemberCallbackFromJava("From Java (named member): " + message); + } + + public static void namespaceAppendJavaToString(String message) + { + namespaceCallbackFromJava("From Java (namespace): " + message); + } + public static void convertToInt(String message) { intCallbackFromJava(Integer.parseInt(message)); diff --git a/tests/auto/corelib/kernel/qjnienvironment/tst_qjnienvironment.cpp b/tests/auto/corelib/kernel/qjnienvironment/tst_qjnienvironment.cpp index 8cf207fc3a..95748f46f7 100644 --- a/tests/auto/corelib/kernel/qjnienvironment/tst_qjnienvironment.cpp +++ b/tests/auto/corelib/kernel/qjnienvironment/tst_qjnienvironment.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <jni.h> @@ -45,6 +20,7 @@ class tst_QJniEnvironment : public QObject Q_OBJECT private slots: + void init(); void jniEnv(); void javaVM(); void registerNativeMethods(); @@ -55,6 +31,14 @@ private slots: void findStaticField(); }; +void tst_QJniEnvironment::init() +{ + // Unless explicitly ignored to test error handling, warning messages + // in this test about a failure to look up a field, method, or class + // make the test fail. + QTest::failOnWarning(QRegularExpression("java.lang.NoSuch.*Error")); +} + void tst_QJniEnvironment::jniEnv() { QJniEnvironment env; @@ -84,17 +68,21 @@ void tst_QJniEnvironment::jniEnv() QVERIFY(!QJniEnvironment::checkAndClearExceptions(env.jniEnv())); // try to find a nonexistent class + QTest::ignoreMessage(QtWarningMsg, QRegularExpression("java.lang.ClassNotFoundException: .*")); QVERIFY(!env->FindClass("this/doesnt/Exist")); QVERIFY(QJniEnvironment::checkAndClearExceptions(env.jniEnv())); // try to find an existing class with QJniEnvironment QJniEnvironment env; QVERIFY(env.findClass("java/lang/Object")); + QVERIFY(env.findClass<jstring>()); // try to find a nonexistent class + QTest::ignoreMessage(QtWarningMsg, QRegularExpression("java.lang.ClassNotFoundException: .*")); QVERIFY(!env.findClass("this/doesnt/Exist")); // clear exception with member function + QTest::ignoreMessage(QtWarningMsg, QRegularExpression("java.lang.ClassNotFoundException: .*")); QVERIFY(!env->FindClass("this/doesnt/Exist")); QVERIFY(env.checkAndClearExceptions()); } @@ -123,12 +111,49 @@ static void callbackFromJava(JNIEnv *env, jobject /*thiz*/, jstring value) Q_UNUSED(env) registerNativesString = QJniObject(value).toString(); } +Q_DECLARE_JNI_NATIVE_METHOD(callbackFromJava); + +static void tediouslyLongNamed_callbackFromJava(JNIEnv *env, jobject /*thiz*/, jstring value) +{ + Q_UNUSED(env) + registerNativesString = QJniObject(value).toString(); +} +Q_DECLARE_JNI_NATIVE_METHOD(tediouslyLongNamed_callbackFromJava, namedCallbackFromJava) static void callbackFromJavaNoCtor(JNIEnv *env, jobject /*thiz*/, jstring value) { Q_UNUSED(env) registerNativesString = QJniObject(value).toString(); } +Q_DECLARE_JNI_NATIVE_METHOD(callbackFromJavaNoCtor); + +class CallbackClass { +public: + static void memberCallbackFromJava(JNIEnv *env, jobject /*thiz*/, jstring value) + { + Q_UNUSED(env) + registerNativesString = QJniObject(value).toString(); + } + Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(memberCallbackFromJava) + + static void tediouslyLongNamed_memberCallbackFromJava(JNIEnv *env, jobject /*thiz*/, + jstring value) + { + Q_UNUSED(env) + registerNativesString = QJniObject(value).toString(); + } + Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(tediouslyLongNamed_memberCallbackFromJava, + namedMemberCallbackFromJava) +}; + +namespace CallbackNamespace { + static void namespaceCallbackFromJava(JNIEnv *env, jobject /*thiz*/, jstring value) + { + Q_UNUSED(env) + registerNativesString = QJniObject(value).toString(); + } + Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(namespaceCallbackFromJava) +} void tst_QJniEnvironment::registerNativeMethods() { @@ -136,11 +161,9 @@ void tst_QJniEnvironment::registerNativeMethods() QJniEnvironment env; { - const JNINativeMethod methods[] { - {"callbackFromJava", "(Ljava/lang/String;)V", reinterpret_cast<void *>(callbackFromJava)} - }; - - QVERIFY(env.registerNativeMethods(javaTestClass, methods, 1)); + QVERIFY(env.registerNativeMethods(javaTestClass, { + Q_JNI_NATIVE_METHOD(callbackFromJava) + })); QJniObject::callStaticMethod<void>(javaTestClass, "appendJavaToString", @@ -150,12 +173,68 @@ void tst_QJniEnvironment::registerNativeMethods() QVERIFY(registerNativesString == QStringLiteral("From Java: Qt")); } - // No default constructor in class + // Named native function { - const JNINativeMethod methods[] {{"callbackFromJavaNoCtor", "(Ljava/lang/String;)V", - reinterpret_cast<void *>(callbackFromJavaNoCtor)}}; + QVERIFY(env.registerNativeMethods(javaTestClass, { + Q_JNI_NATIVE_METHOD(tediouslyLongNamed_callbackFromJava) + })); + + QJniObject::callStaticMethod<void>(javaTestClass, + "namedAppendJavaToString", + "(Ljava/lang/String;)V", + QtString.object<jstring>()); + QTest::qWait(200); + QVERIFY(registerNativesString == QStringLiteral("From Java (named): Qt")); + } - QVERIFY(env.registerNativeMethods(javaTestClassNoCtor, methods, 1)); + // Static class member as callback + { + QVERIFY(env.registerNativeMethods(javaTestClass, { + Q_JNI_NATIVE_SCOPED_METHOD(memberCallbackFromJava, CallbackClass) + })); + + QJniObject::callStaticMethod<void>(javaTestClass, + "memberAppendJavaToString", + "(Ljava/lang/String;)V", + QtString.object<jstring>()); + QTest::qWait(200); + QVERIFY(registerNativesString == QStringLiteral("From Java (member): Qt")); + } + + // Static named class member as callback + { + QVERIFY(env.registerNativeMethods(javaTestClass, { + Q_JNI_NATIVE_SCOPED_METHOD(tediouslyLongNamed_memberCallbackFromJava, + CallbackClass) + })); + + QJniObject::callStaticMethod<void>(javaTestClass, + "namedMemberAppendJavaToString", + "(Ljava/lang/String;)V", + QtString.object<jstring>()); + QTest::qWait(200); + QVERIFY(registerNativesString == QStringLiteral("From Java (named member): Qt")); + } + + // Function generally just in namespace as callback + { + QVERIFY(env.registerNativeMethods(javaTestClass, { + Q_JNI_NATIVE_SCOPED_METHOD(namespaceCallbackFromJava, CallbackNamespace) + })); + + QJniObject::callStaticMethod<void>(javaTestClass, + "namespaceAppendJavaToString", + "(Ljava/lang/String;)V", + QtString.object<jstring>()); + QTest::qWait(200); + QVERIFY(registerNativesString == QStringLiteral("From Java (namespace): Qt")); + } + + // No default constructor in class + { + QVERIFY(env.registerNativeMethods(javaTestClassNoCtor, { + Q_JNI_NATIVE_METHOD(callbackFromJavaNoCtor) + })); QJniObject::callStaticMethod<void>(javaTestClassNoCtor, "appendJavaToString", @@ -171,17 +250,16 @@ static void intCallbackFromJava(JNIEnv *env, jobject /*thiz*/, jint value) Q_UNUSED(env) registerNativeInteger = static_cast<int>(value); } +Q_DECLARE_JNI_NATIVE_METHOD(intCallbackFromJava); void tst_QJniEnvironment::registerNativeMethodsByJclass() { - const JNINativeMethod methods[] { - { "intCallbackFromJava", "(I)V", reinterpret_cast<void *>(intCallbackFromJava) } - }; - QJniEnvironment env; jclass clazz = env.findClass(javaTestClass); QVERIFY(clazz != 0); - QVERIFY(env.registerNativeMethods(clazz, methods, 1)); + QVERIFY(env.registerNativeMethods(clazz, { + Q_JNI_NATIVE_METHOD(intCallbackFromJava) + })); QCOMPARE(registerNativeInteger, 0); @@ -202,7 +280,12 @@ void tst_QJniEnvironment::findMethod() jmethodID methodId = env.findMethod(clazz, "toString", "()Ljava/lang/String;"); QVERIFY(methodId != nullptr); + // existing method + methodId = env.findMethod<jstring>(clazz, "toString"); + QVERIFY(methodId != nullptr); + // invalid signature + QTest::ignoreMessage(QtWarningMsg, QRegularExpression("java.lang.NoSuchMethodError: .*")); jmethodID invalid = env.findMethod(clazz, "unknown", "()I"); QVERIFY(invalid == nullptr); // check that all exceptions are already cleared @@ -219,14 +302,22 @@ void tst_QJniEnvironment::findStaticMethod() jmethodID staticMethodId = env.findStaticMethod(clazz, "parseInt", "(Ljava/lang/String;)I"); QVERIFY(staticMethodId != nullptr); + // existing method + staticMethodId = env.findStaticMethod<jint, jstring>(clazz, "parseInt"); + QVERIFY(staticMethodId != nullptr); + QJniObject parameter = QJniObject::fromString("123"); jint result = QJniObject::callStaticMethod<jint>(clazz, staticMethodId, parameter.object<jstring>()); QCOMPARE(result, 123); // invalid method + QTest::ignoreMessage(QtWarningMsg, QRegularExpression("java.lang.NoSuchMethodError: .*")); jmethodID invalid = env.findStaticMethod(clazz, "unknown", "()I"); QVERIFY(invalid == nullptr); + QTest::ignoreMessage(QtWarningMsg, QRegularExpression("java.lang.NoSuchMethodError: .*")); + invalid = env.findStaticMethod<jint>(clazz, "unknown"); + QVERIFY(invalid == nullptr); // check that all exceptions are already cleared QVERIFY(!env.checkAndClearExceptions()); } @@ -240,6 +331,8 @@ void tst_QJniEnvironment::findField() // valid field jfieldID validId = env.findField(clazz, "INT_FIELD", "I"); QVERIFY(validId != nullptr); + validId = env.findField<jint>(clazz, "INT_FIELD"); + QVERIFY(validId != nullptr); jmethodID constructorId = env.findMethod(clazz, "<init>", "()V"); QVERIFY(constructorId != nullptr); @@ -250,6 +343,7 @@ void tst_QJniEnvironment::findField() QVERIFY(value == 123); // invalid signature + QTest::ignoreMessage(QtWarningMsg, QRegularExpression("java.lang.NoSuchFieldError: .*")); jfieldID invalidId = env.findField(clazz, "unknown", "I"); QVERIFY(invalidId == nullptr); // check that all exceptions are already cleared @@ -265,12 +359,15 @@ void tst_QJniEnvironment::findStaticField() // valid field jfieldID validId = env.findStaticField(clazz, "S_INT_FIELD", "I"); QVERIFY(validId != nullptr); + validId = env.findStaticField<jint>(clazz, "S_INT_FIELD"); + QVERIFY(validId != nullptr); int size = env->GetStaticIntField(clazz, validId); QVERIFY(!env.checkAndClearExceptions()); QVERIFY(size == 321); // invalid signature + QTest::ignoreMessage(QtWarningMsg, QRegularExpression("java.lang.NoSuchFieldError: .*")); jfieldID invalidId = env.findStaticField(clazz, "unknown", "I"); QVERIFY(invalidId == nullptr); // check that all exceptions are already cleared |