diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4020517..884de76 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,9 +13,12 @@ on: env: BUILD_TYPE: Release + NDK_VER: 21.3.6528147 + NDK_ARCH: x86_64 + NDK_API: 29 jobs: - build: + desktop: runs-on: ${{ matrix.os }} strategy: fail-fast: false @@ -139,10 +142,58 @@ jobs: - name: Build and Test JniGen shell: bash - run: cmake --build build --config $BUILD_TYPE --target run-java-tests + run: cmake --build build --config $BUILD_TYPE --target test-jnigen - # - name: Test JniGen - # working-directory: ${{github.workspace}}/jnigen - # shell: bash - # run: ./gradlew -PbuildDir=build -Pcode.version=SNAPSHOT test + android: + runs-on: macos-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: AVD cache + uses: actions/cache@v3 + id: avd-cache + with: + path: | + ~/.android/avd/* + ~/.android/adb* + key: avd-${{env.NDK_VER}}-${{env.NDK_ARCH}}-${{env.NDK_API}} + + - name: Create AVD and generate snapshot for caching + if: steps.avd-cache.outputs.cache-hit != 'true' + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: ${{env.NDK_API}} + arch: ${{env.NDK_ARCH}} + target: google_apis + ndk: ${{env.NDK_VER}} + force-avd-creation: false + emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none + disable-animations: false + script: echo "Generated AVD snapshot for caching." + + - name: Configure, Build and Test + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: ${{env.NDK_API}} + arch: ${{env.NDK_ARCH}} + target: google_apis + ndk: ${{env.NDK_VER}} + emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none + disable-animations: true + script: | + echo "::group::Configure" + cmake -S . -B build -DCMAKE_BUILD_TYPE:STRING=$BUILD_TYPE -DCMAKE_TOOLCHAIN_FILE:FILEPATH=$ANDROID_SDK_ROOT/ndk/$NDK_VER/build/cmake/android.toolchain.cmake -DANDROID_ABI:STRING=$NDK_ARCH -DANDROID_PLATFORM:STRING=19 -DANDROID_STL:STRING=c++_static + echo "::endgroup::" + echo "::group::Build and Test Native" + cmake --build build --config $BUILD_TYPE --target run-app + echo "::endgroup::" + echo "::group::Build and Test JniGen" + cmake --build build --config $BUILD_TYPE --target test-jnigen + echo "::endgroup::" + + + + diff --git a/tests/.gitignore b/tests/.gitignore index 9e62d7e..4ea0d2a 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1,4 +1,2 @@ -/local.properties -/gradle.properties +local.properties /src/cpp/generated -/xcode \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1c77edb..96110e1 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -16,33 +16,21 @@ cmake_minimum_required(VERSION 3.16) -project(test) - -find_package(Java COMPONENTS Development REQUIRED) - add_subdirectory("src/cpp" ${CMAKE_CURRENT_BINARY_DIR}/test) add_custom_target(build-jnigen - COMMAND ${CMAKE_CURRENT_LIST_DIR}/gradlew -Pcode.version=SNAPSHOT publishToMavenLocal + COMMAND ./gradlew -Pcode.version=SNAPSHOT publishToMavenLocal WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/../jnigen ) -add_custom_target(run-java-tests ALL - COMMAND ${CMAKE_CURRENT_LIST_DIR}/gradlew -Pcode.version=SNAPSHOT test +add_custom_target(test-jnigen ALL + COMMAND ./gradlew -Pcode.version=SNAPSHOT test WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/../jnigen ) -add_custom_target(javabuild - DEPENDS build-jnigen - COMMAND ${CMAKE_CURRENT_LIST_DIR}/gradlew -PbuildDir=${CMAKE_CURRENT_BINARY_DIR}/java assemble - WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} -) +if (${CMAKE_SYSTEM_NAME} STREQUAL Android) + add_subdirectory("android") +else() + add_subdirectory("desktop") +endif() -add_dependencies(smjnitests javabuild) - -add_custom_target(run-jar ALL - DEPENDS javabuild smjnitests - COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_BINARY_DIR}/java - COMMAND ${CMAKE_COMMAND} -E env "LD_LIBRARY_PATH=${CMAKE_CURRENT_BINARY_DIR}/java:$ENV{LD_LIBRARY_PATH}" ${Java_JAVA_EXECUTABLE} -jar smjnitests.jar - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/java -) diff --git a/tests/android/.gitignore b/tests/android/.gitignore new file mode 100644 index 0000000..3166b90 --- /dev/null +++ b/tests/android/.gitignore @@ -0,0 +1 @@ +.cxx/ diff --git a/tests/android/CMakeLists.txt b/tests/android/CMakeLists.txt new file mode 100644 index 0000000..e5525c6 --- /dev/null +++ b/tests/android/CMakeLists.txt @@ -0,0 +1,49 @@ +# +# Copyright 2023 SmJNI Contributors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +cmake_minimum_required(VERSION 3.16) + +find_package (Python3 COMPONENTS Interpreter REQUIRED) + +add_custom_target(javabuild + DEPENDS build-jnigen + COMMAND ${CMAKE_CURRENT_LIST_DIR}/gradlew -PbuildDir=${CMAKE_CURRENT_BINARY_DIR}/gradle :app:compileDebugJavaWithJavac + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} +) + +add_dependencies(smjnitests javabuild) + +add_custom_target(androidbuild ALL + DEPENDS javabuild smjnitests + COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_LIST_DIR}/app/libs/${ANDROID_ABI} + COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_LIST_DIR}/app/libs/${ANDROID_ABI}/$ + COMMAND ${CMAKE_CURRENT_LIST_DIR}/gradlew -PbuildDir=${CMAKE_CURRENT_BINARY_DIR}/gradle :app:assembleDebug + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} +) + +set(ANDROID_SDK_DIR ${CMAKE_ANDROID_NDK}/../..) +set(ADB ${ANDROID_SDK_DIR}/platform-tools/adb) + + +add_custom_target(run-app ALL + DEPENDS androidbuild smjnitests + COMMAND ${ADB} install -r -d ${CMAKE_CURRENT_BINARY_DIR}/gradle/outputs/apk/debug/app-debug.apk + COMMAND ${ADB} shell content call --uri content://com.example.smjni_test.provider --method blah + COMMAND ${ADB} pull /sdcard/Download/smjni_test/results.json ${CMAKE_CURRENT_BINARY_DIR}/results.json + COMMAND ${Python3_EXECUTABLE} parse-output.py ${CMAKE_CURRENT_BINARY_DIR}/results.json + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} +) + diff --git a/tests/android/app/build.gradle b/tests/android/app/build.gradle new file mode 100644 index 0000000..5b285fe --- /dev/null +++ b/tests/android/app/build.gradle @@ -0,0 +1,110 @@ +plugins { + id 'com.android.application' +} + +//JniGen settings +def jniGenProps = new Object() { + def generatedPath = "../../src/cpp/generated" + def outputListName = "outputs.txt" + def additionalClasses = ["java.lang.AssertionError"] +} + +dependencies { + + annotationProcessor("io.github.gershnik:smjni-jnigen-processor:SNAPSHOT") + + compileOnly 'io.github.gershnik:smjni-jnigen-annotations:SNAPSHOT' + + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + implementation 'androidx.appcompat:appcompat:1.6.1' + implementation 'com.google.android.material:material:1.10.0' + implementation 'org.junit.jupiter:junit-jupiter-api:5.10.0' + + + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.5' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' +} + +android { + compileSdk 34 + namespace 'com.example.smjni_test' + + defaultConfig { + applicationId "com.example.smjni_test" + minSdk 16 + targetSdk 34 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + + javaCompileOptions { + annotationProcessorOptions { + arguments = [ + "smjni.jnigen.dest.path" : file(jniGenProps.generatedPath).path, + "smjni.jnigen.own.dest.path" : "true", + "smjni.jnigen.output.list.name": jniGenProps.outputListName, + "smjni.jnigen.expose.extra" : jniGenProps.additionalClasses.join(";").toString() + ] + } + } + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + sourceSets { + main.java.srcDirs += '../../src/java' + main.jniLibs.srcDirs += 'libs' + } + + packaging { + resources.excludes += ["META-INF/LICENSE.md", "META-INF/LICENSE-notice.md"] + } +} + + +android.applicationVariants.all { variant -> + + variant.javaCompileProvider.get().outputs.upToDateWhen { + + def jniGenOutputList = file("${jniGenProps.generatedPath}/${jniGenProps.outputListName}") + + if (!jniGenOutputList.exists()) { + return false + } + + for(line in jniGenOutputList) { + if (!file("${jniGenProps.generatedPath}/$line").exists()) { + return false + } + } + return true + } +} + +task cleanJNIHeaders(type: Delete) { + delete file("${jniGenProps.generatedPath}") +} +clean.dependsOn cleanJNIHeaders + +tasks.whenTaskAdded { theTask -> + def match = theTask.name =~ ~/^buildCMake([^\[]*).*$/ + if (match) { + def config + switch(match.group(1)) { + case "RelWithDebInfo": config = "Release"; break + default: config = match.group(1); break + } + theTask.dependsOn "compile${config}JavaWithJavac" + } +} diff --git a/tests/android/app/libs/x86_64/libsmjnitests.so b/tests/android/app/libs/x86_64/libsmjnitests.so new file mode 100755 index 0000000..96cc66d Binary files /dev/null and b/tests/android/app/libs/x86_64/libsmjnitests.so differ diff --git a/tests/android/app/proguard-rules.pro b/tests/android/app/proguard-rules.pro new file mode 100644 index 0000000..bb7d3cf --- /dev/null +++ b/tests/android/app/proguard-rules.pro @@ -0,0 +1,26 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile + +-keep @smjni.jnigen.ExposeToNative class * +-keepclassmembers class * { + @smjni.jnigen.CalledByNative *; +} diff --git a/tests/android/app/src/main/AndroidManifest.xml b/tests/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..da4d179 --- /dev/null +++ b/tests/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/android/app/src/main/java/com/example/smjni_test/TestContentProvider.java b/tests/android/app/src/main/java/com/example/smjni_test/TestContentProvider.java new file mode 100644 index 0000000..282c1d2 --- /dev/null +++ b/tests/android/app/src/main/java/com/example/smjni_test/TestContentProvider.java @@ -0,0 +1,103 @@ +package com.example.smjni_test; + +import android.content.ContentProvider; +import android.content.ContentValues; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.util.Objects; + +import smjni.tests.TestSimpleJNI; + +public class TestContentProvider extends ContentProvider { + public TestContentProvider() { + } + + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + throw new UnsupportedOperationException("Not implemented"); + } + + @Override + public String getType(Uri uri) { + throw new UnsupportedOperationException("Not implemented"); + } + + @Override + public Uri insert(Uri uri, ContentValues values) { + throw new UnsupportedOperationException("Not implemented"); + } + + @Override + public boolean onCreate() { + return false; + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, + String[] selectionArgs, String sortOrder) { + throw new UnsupportedOperationException("Not implemented"); + } + + @Override + public int update(Uri uri, ContentValues values, String selection, + String[] selectionArgs) { + throw new UnsupportedOperationException("Not implemented"); + } + + @Nullable + @Override + public Bundle call(@NonNull String method, @Nullable String arg, @Nullable Bundle extras) { + Bundle ret = new Bundle(); + try { + File resultDir = new File("/sdcard/Download/smjni_test"); + resultDir.mkdirs(); + File resultFile = new File(resultDir, "results.json"); + resultFile.delete(); + + File outFile = new File(Objects.requireNonNull(getContext()).getFilesDir(), "results.txt"); + outFile.delete(); + int res = TestSimpleJNI.androidMain(new String[]{"-o", outFile.getAbsolutePath()}); + JSONObject json = new JSONObject(); + ret.putInt("result", res); + json.put("result", res); + StringBuilder stringBuilder = new StringBuilder(); + String ls = System.getProperty("line.separator"); + try { + BufferedReader reader = new BufferedReader(new FileReader(outFile)); + String line; + while ((line = reader.readLine()) != null) { + stringBuilder.append(line); + stringBuilder.append(ls); + } + String text = stringBuilder.toString(); + ret.putString("output", text); + json.put("output", text); + } catch (IOException ex) { + ret.putString("output", ""); + json.put("output", ""); + } + BufferedWriter writer = new BufferedWriter(new FileWriter(resultFile)); + writer.write(json.toString()); + writer.flush(); + } catch (IOException ex) { + throw new RuntimeException(ex); + } catch (JSONException ex) { + throw new RuntimeException(ex); + } + return null; + } +} \ No newline at end of file diff --git a/tests/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/tests/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/tests/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/tests/android/app/src/main/res/drawable/ic_launcher_background.xml b/tests/android/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/tests/android/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/tests/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..eca70cf --- /dev/null +++ b/tests/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/tests/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/tests/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..eca70cf --- /dev/null +++ b/tests/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/tests/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/tests/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..a571e60 Binary files /dev/null and b/tests/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/tests/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/tests/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000..61da551 Binary files /dev/null and b/tests/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/tests/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/tests/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..c41dd28 Binary files /dev/null and b/tests/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/tests/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/tests/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000..db5080a Binary files /dev/null and b/tests/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/tests/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/tests/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..6dba46d Binary files /dev/null and b/tests/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/tests/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/tests/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000..da31a87 Binary files /dev/null and b/tests/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/tests/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/tests/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..15ac681 Binary files /dev/null and b/tests/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/tests/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/tests/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..b216f2d Binary files /dev/null and b/tests/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/tests/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/tests/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..f25a419 Binary files /dev/null and b/tests/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/tests/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/tests/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..e96783c Binary files /dev/null and b/tests/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/tests/android/app/src/main/res/values-night/themes.xml b/tests/android/app/src/main/res/values-night/themes.xml new file mode 100644 index 0000000..c47e235 --- /dev/null +++ b/tests/android/app/src/main/res/values-night/themes.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/tests/android/app/src/main/res/values/colors.xml b/tests/android/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..f8c6127 --- /dev/null +++ b/tests/android/app/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/tests/android/app/src/main/res/values/strings.xml b/tests/android/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..cfdfc44 --- /dev/null +++ b/tests/android/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + smjni_test + \ No newline at end of file diff --git a/tests/android/app/src/main/res/values/themes.xml b/tests/android/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..d55f1e5 --- /dev/null +++ b/tests/android/app/src/main/res/values/themes.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/tests/android/build.gradle b/tests/android/build.gradle new file mode 100644 index 0000000..c9d9919 --- /dev/null +++ b/tests/android/build.gradle @@ -0,0 +1,28 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +buildscript { + ext.kotlin_version = "1.9.0" + repositories { + mavenLocal() + google() + mavenCentral() + } + dependencies { + classpath "com.android.tools.build:gradle:8.1.2" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + mavenLocal() + google() + mavenCentral() + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} \ No newline at end of file diff --git a/tests/android/gradle.properties b/tests/android/gradle.properties new file mode 100644 index 0000000..c09e1e3 --- /dev/null +++ b/tests/android/gradle.properties @@ -0,0 +1,17 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app"s APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true diff --git a/tests/gradle/wrapper/gradle-wrapper.jar b/tests/android/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from tests/gradle/wrapper/gradle-wrapper.jar rename to tests/android/gradle/wrapper/gradle-wrapper.jar diff --git a/tests/gradle/wrapper/gradle-wrapper.properties b/tests/android/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from tests/gradle/wrapper/gradle-wrapper.properties rename to tests/android/gradle/wrapper/gradle-wrapper.properties diff --git a/tests/gradlew b/tests/android/gradlew similarity index 100% rename from tests/gradlew rename to tests/android/gradlew diff --git a/tests/gradlew.bat b/tests/android/gradlew.bat similarity index 100% rename from tests/gradlew.bat rename to tests/android/gradlew.bat diff --git a/tests/android/parse-output.py b/tests/android/parse-output.py new file mode 100644 index 0000000..5aac504 --- /dev/null +++ b/tests/android/parse-output.py @@ -0,0 +1,8 @@ +import sys +import json + +with open(sys.argv[1], 'r') as resultsFile: + results = json.load(resultsFile) + +print(results['output']) +sys.exit(results['result']) diff --git a/tests/android/settings.gradle b/tests/android/settings.gradle new file mode 100644 index 0000000..46ffb4a --- /dev/null +++ b/tests/android/settings.gradle @@ -0,0 +1,2 @@ +include ':app' +rootProject.name = "smjni_test" \ No newline at end of file diff --git a/tests/desktop/CMakeLists.txt b/tests/desktop/CMakeLists.txt new file mode 100644 index 0000000..9b63f41 --- /dev/null +++ b/tests/desktop/CMakeLists.txt @@ -0,0 +1,34 @@ +# +# Copyright 2023 SmJNI Contributors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +cmake_minimum_required(VERSION 3.16) + +find_package(Java COMPONENTS Development REQUIRED) + +add_custom_target(javabuild + DEPENDS build-jnigen + COMMAND ${CMAKE_CURRENT_LIST_DIR}/gradlew -PbuildDir=${CMAKE_CURRENT_BINARY_DIR}/java assemble + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} +) + +add_dependencies(smjnitests javabuild) + +add_custom_target(run-jar ALL + DEPENDS javabuild smjnitests + COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_BINARY_DIR}/java + COMMAND ${CMAKE_COMMAND} -E env "LD_LIBRARY_PATH=${CMAKE_CURRENT_BINARY_DIR}/java:$ENV{LD_LIBRARY_PATH}" ${Java_JAVA_EXECUTABLE} -jar smjnitests.jar + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/java +) diff --git a/tests/build.gradle b/tests/desktop/build.gradle similarity index 96% rename from tests/build.gradle rename to tests/desktop/build.gradle index cc76554..09ccfb8 100644 --- a/tests/build.gradle +++ b/tests/desktop/build.gradle @@ -34,7 +34,7 @@ apply plugin: 'java' //JniGen settings def jniGenProps = new Object() { - def generatedPath = "src/cpp/generated" + def generatedPath = "../src/cpp/generated" def outputListName = "outputs.txt" def additionalClasses = ["java.lang.AssertionError"] } @@ -62,7 +62,7 @@ tasks.withType(JavaCompile).configureEach { } sourceSets { - main.java.srcDirs = ['src/java'] + main.java.srcDirs = ['../src/java'] } tasks.register('cleanJNIHeaders', Delete) { diff --git a/tests/desktop/gradle/wrapper/gradle-wrapper.jar b/tests/desktop/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..5c2d1cf Binary files /dev/null and b/tests/desktop/gradle/wrapper/gradle-wrapper.jar differ diff --git a/tests/desktop/gradle/wrapper/gradle-wrapper.properties b/tests/desktop/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..5b09d39 --- /dev/null +++ b/tests/desktop/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Wed Oct 25 23:33:07 PDT 2023 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/tests/desktop/gradlew b/tests/desktop/gradlew new file mode 100755 index 0000000..cccdd3d --- /dev/null +++ b/tests/desktop/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/tests/desktop/gradlew.bat b/tests/desktop/gradlew.bat new file mode 100644 index 0000000..f955316 --- /dev/null +++ b/tests/desktop/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/tests/settings.gradle b/tests/desktop/settings.gradle similarity index 100% rename from tests/settings.gradle rename to tests/desktop/settings.gradle diff --git a/tests/src/cpp/CMakeLists.txt b/tests/src/cpp/CMakeLists.txt index b745991..748b698 100644 --- a/tests/src/cpp/CMakeLists.txt +++ b/tests/src/cpp/CMakeLists.txt @@ -20,7 +20,7 @@ include(FetchContent) FetchContent_Declare(catch2 GIT_REPOSITORY https://github.com/catchorg/Catch2.git - GIT_TAG v3.3.2 + GIT_TAG v3.4.0 GIT_PROGRESS TRUE ) @@ -31,6 +31,7 @@ add_library(smjnitests SHARED EXCLUDE_FROM_ALL) target_link_libraries(smjnitests PRIVATE smjni::smjni Catch2::Catch2 + $<$:log> ) set_property(TARGET smjnitests PROPERTY CXX_STANDARD 17) @@ -42,13 +43,18 @@ set_property(TARGET smjnitests PROPERTY POSITION_INDEPENDENT_CODE ON) set_property(TARGET Catch2 PROPERTY POSITION_INDEPENDENT_CODE ON) target_compile_options(smjnitests - PRIVATE +PRIVATE $<$:/utf-8;/W4;/wd4100;/wd4127> $<$:-Wall;-Wextra;-Wno-unused-parameter> $<$:-Wall;-Wextra;-Wno-unused-parameter> $<$:-Wall;-Wextra;-Wno-unused-parameter;-Wno-unused-but-set-parameter> ) +target_link_options(smjnitests +PRIVATE + $<$:-Wl,--export-dynamic> +) + file(GLOB GENERATED_FILES CONFIGURE_DEPENDS generated/*.h) target_sources(smjnitests PRIVATE diff --git a/tests/src/cpp/smjnitests.cpp b/tests/src/cpp/smjnitests.cpp index 09fcb5d..62efcaa 100644 --- a/tests/src/cpp/smjnitests.cpp +++ b/tests/src/cpp/smjnitests.cpp @@ -77,7 +77,8 @@ jint JNICALL TestSimpleJNI::testMain(JNIEnv * env, jclass, jstringArray args) return &arg[0]; }); - return Catch::Session().run(int(cArgs.size()), &cArgs[0]); + static Catch::Session session; + return session.run(int(cArgs.size()), &cArgs[0]); } diff --git a/tests/src/java/smjni/tests/TestSimpleJNI.java b/tests/src/java/smjni/tests/TestSimpleJNI.java index ab6fb75..4bd2ec8 100644 --- a/tests/src/java/smjni/tests/TestSimpleJNI.java +++ b/tests/src/java/smjni/tests/TestSimpleJNI.java @@ -28,7 +28,7 @@ @ExposeToNative(className="TestSimpleJNI") -class TestSimpleJNI { +public class TestSimpleJNI { @ExposeToNative(typeName="jBase", className="Base") static class Base @@ -74,7 +74,12 @@ int instanceMethod(int val) public static void main(String[] args) { System.loadLibrary("smjnitests"); - testMain(args); + System.exit(testMain(args)); + } + + public static int androidMain(String[] args) { + System.loadLibrary("smjnitests"); + return testMain(args); } private static native int testMain(String[] args);