diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt index 60b1506..a202895 100644 --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -1,15 +1,17 @@ add_definitions(-DSOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}") +ecm_add_test(jnisignaturetest.cpp LINK_LIBRARIES Qt5::Test) + ecm_add_test(pkpassmanagertest.cpp LINK_LIBRARIES Qt5::Test itinerary) ecm_add_test(reservationmanagertest.cpp LINK_LIBRARIES Qt5::Test itinerary) ecm_add_test(applicationcontrollertest.cpp LINK_LIBRARIES Qt5::Test itinerary) ecm_add_test(tripgrouptest.cpp LINK_LIBRARIES Qt5::Test itinerary) ecm_add_test(timelinemodeltest.cpp modelverificationpoint.cpp TEST_NAME timelinemodeltest LINK_LIBRARIES Qt5::Test itinerary) ecm_add_test(tripgroupproxytest.cpp modelverificationpoint.cpp TEST_NAME tripgroupproxytest LINK_LIBRARIES Qt5::Test itinerary) ecm_add_test(tripgroupinfoprovidertest.cpp TEST_NAME tripgroupinfoprovidertest LINK_LIBRARIES Qt5::Test itinerary) ecm_add_test(publictransporttest.cpp TEST_NAME publictransporttest LINK_LIBRARIES Qt5::Test itinerary) ecm_add_test(timelinedelegatecontrollertest.cpp TEST_NAME timelinedelegatecontrollertest LINK_LIBRARIES Qt5::Test itinerary) ecm_add_test(documentmanagertest.cpp TEST_NAME documentmanagertest LINK_LIBRARIES Qt5::Test itinerary) ecm_add_test(weathertest.cpp LINK_LIBRARIES Qt5::Test itinerary-weather) target_include_directories(weathertest PRIVATE ${CMAKE_BINARY_DIR}) diff --git a/autotests/jnisignaturetest.cpp b/autotests/jnisignaturetest.cpp new file mode 100644 index 0000000..f432201 --- /dev/null +++ b/autotests/jnisignaturetest.cpp @@ -0,0 +1,48 @@ +/* + Copyright (C) 2019 Volker Krause + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include <../src/kandroidextras/jnisignature.h> +#include <../src/kandroidextras/jnitypes.h> + +#include + +using namespace KAndroidExtras; + +class JniSignatureTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void testSignature() + { + QCOMPARE((const char*)Jni::signature(), "Z"); + QCOMPARE((const char*)Jni::signature(), "([F)V"); + QCOMPARE((const char*)Jni::signature(), "(Ljava/lang/String;)V"); + QCOMPARE((const char*)Jni::signature(), "()Ljava/lang/String;"); + QCOMPARE((const char*)Jni::signature(), "(Ljava/lang/String;[Z)Landroid/content/Intent;"); + } + + void testImplementationDetails() + { + static_assert(Internal::static_strlen("Hello!") == 6, ""); + QCOMPARE(java::lang::String::jniName(), "java/lang/String"); + QCOMPARE(((const char*)Internal::staticStringFromJniType>::value()), "java/lang/String"); + } +}; + +QTEST_GUILESS_MAIN(JniSignatureTest) + +#include "jnisignaturetest.moc" diff --git a/src/kandroidextras/jnisignature.h b/src/kandroidextras/jnisignature.h new file mode 100644 index 0000000..aade066 --- /dev/null +++ b/src/kandroidextras/jnisignature.h @@ -0,0 +1,117 @@ +/* + Copyright (C) 2019 Volker Krause + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef KANDROIDEXTRAS_JNISIGNATURE_H +#define KANDROIDEXTRAS_JNISIGNATURE_H + +#include +#include + +namespace KAndroidExtras { + +namespace Internal { + +/** Compile-time concat-able string. */ +template +struct StaticString { + inline operator const char*() const + { + static const char data[] = { String..., 0 }; + return data; + } +}; + +/** Compile-time strlen. */ +constexpr inline int static_strlen(const char *str) +{ + return str[0] == '\0' ? 0 : static_strlen(str + 1) + 1; +} + +/** Compile-time concat for two StaticString. */ +template +constexpr inline auto static_concat(const StaticString&, const StaticString&) +{ + return StaticString(); +} + +/** Compile-time concapt for N StaticString. */ +template +constexpr inline auto static_concat(const String1& str1, const String2& str2, const Strings&... strs) +{ + return static_concat(static_concat(str1, str2), strs...); +} + +/** Conversion from const char* literals to StaticString. */ +template struct staticStringFromJniType; +template +struct staticStringFromJniType> +{ + typedef StaticString value; +}; + +/** Meta function for assembling JNI signatures. */ +template +struct JniSignature +{ + constexpr inline auto operator()() const + { + using namespace Internal; + return static_concat(StaticString<'L'>(), typename staticStringFromJniType>::value(), StaticString<';'>()); + } +}; + +template <> struct JniSignature { constexpr inline auto operator()() const { return StaticString<'Z'>(); } }; +template <> struct JniSignature { constexpr inline auto operator()() const { return StaticString<'B'>(); } }; +template <> struct JniSignature { constexpr inline auto operator()() const { return StaticString<'C'>(); } }; +template <> struct JniSignature { constexpr inline auto operator()() const { return StaticString<'S'>(); } }; +template <> struct JniSignature { constexpr inline auto operator()() const { return StaticString<'I'>(); } }; +template <> struct JniSignature { constexpr inline auto operator()() const { return StaticString<'J'>(); } }; +template <> struct JniSignature { constexpr inline auto operator()() const { return StaticString<'F'>(); } }; +template <> struct JniSignature { constexpr inline auto operator()() const { return StaticString<'D'>(); } }; +template <> struct JniSignature { constexpr inline auto operator()() const { return StaticString<'V'>(); } }; + +template +struct JniSignature +{ + constexpr inline auto operator()() const + { + using namespace Internal; + return static_concat(StaticString<'['>(), JniSignature()()); + } +}; + +template +struct JniSignature +{ + constexpr inline auto operator()() const + { + using namespace Internal; + return static_concat(StaticString<'('>(), JniSignature()()..., StaticString<')'>(), JniSignature()()); + } +}; +} + +/** Helper methods to deal with JNI. */ +namespace Jni +{ + /** Returns the JNI signature string for the template argument types. */ + template constexpr __attribute__((__unused__)) Internal::JniSignature signature = {}; +} + +} + +#endif // KANDROIDEXTRAS_JNISIGNATURE_H diff --git a/src/kandroidextras/jnitypes.h b/src/kandroidextras/jnitypes.h new file mode 100644 index 0000000..7bfd8e9 --- /dev/null +++ b/src/kandroidextras/jnitypes.h @@ -0,0 +1,58 @@ +/* + Copyright (C) 2019 Volker Krause + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef KANDROIDEXTRAS_JNITYPES_H +#define KANDROIDEXTRAS_JNITYPES_H + +// determine how many elements are in __VA_ARGS__ +#define PP_NARG(...) PP_NARG_(__VA_ARGS__, PP_RSEQ_N()) +#define PP_NARG_(...) PP_ARG_N(__VA_ARGS__) +#define PP_ARG_N(_1, _2, _3, _4, _5, _6, _7, N, ...) N +#define PP_RSEQ_N() 7, 6, 5, 4, 3, 2, 1, 0 + +// preprocessor-level token concat +#define PP_CONCAT(arg1, arg2) PP_CONCAT1(arg1, arg2) +#define PP_CONCAT1(arg1, arg2) PP_CONCAT2(arg1, arg2) +#define PP_CONCAT2(arg1, arg2) arg1##arg2 + +// preprocessor "iteration" +#define JNI_TYPE_1(name, type, ...) \ + struct type { static constexpr const char* jniName() { return name #type; } }; +#define JNI_TYPE_2(name, type, ...) \ + namespace type { JNI_TYPE_1(name #type "/", __VA_ARGS__) } +#define JNI_TYPE_3(name, type, ...) \ + namespace type { JNI_TYPE_2(name #type "/", __VA_ARGS__) } +#define JNI_TYPE_4(name, type, ...) \ + namespace type { JNI_TYPE_3(name #type "/", __VA_ARGS__) } +#define JNI_TYPE_5(name, type, ...) \ + namespace type { JNI_TYPE_4(name #type "/", __VA_ARGS__) } +#define JNI_TYPE_6(name, type, ...) \ + namespace type { JNI_TYPE_5(name #type "/", __VA_ARGS__) } +#define JNI_TYPE_7(name, type, ...) \ + namespace type { JNI_TYPE_6(#type "/", __VA_ARGS__) } +#define JNI_TYPE_(N, name, ...) PP_CONCAT(JNI_TYPE_, N)(name, __VA_ARGS__) + +/** Macro to define Java types with their corresponding JNI signature strings. */ +#define JNI_TYPE(...) JNI_TYPE_(PP_NARG(__VA_ARGS__), "", __VA_ARGS__) + + +// type declarations +JNI_TYPE(android, content, Intent) +JNI_TYPE(android, net, Uri) +JNI_TYPE(java, lang, String) + +#endif // KANDROIDEXTRAS_JNITYPES_H