diff --git a/conformance/android/build.gradle.kts b/conformance/android/build.gradle.kts
new file mode 100644
index 00000000..019c29d2
--- /dev/null
+++ b/conformance/android/build.gradle.kts
@@ -0,0 +1,23 @@
+plugins {
+ id("com.android.application")
+}
+
+repositories {
+ mavenCentral()
+ mavenLocal()
+ google()
+}
+
+android {
+ namespace = "pbandk.conformance"
+ compileSdk = 36
+
+ defaultConfig {
+ minSdk = 21
+ }
+}
+
+dependencies {
+ implementation(project(":conformance:conformance-jvm"))
+}
+
diff --git a/conformance/android/run.sh b/conformance/android/run.sh
new file mode 100755
index 00000000..67e28469
--- /dev/null
+++ b/conformance/android/run.sh
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+
+set -e
+set -o pipefail
+
+exec adb shell "CLASSPATH=/data/local/tmp/conformance.apk app_process . pbandk.conformance.MainKt"
\ No newline at end of file
diff --git a/conformance/android/src/main/AndroidManifest.xml b/conformance/android/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..099dea46
--- /dev/null
+++ b/conformance/android/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/conformance/lib/build.gradle.kts b/conformance/lib/build.gradle.kts
index e8373deb..3505ff46 100644
--- a/conformance/lib/build.gradle.kts
+++ b/conformance/lib/build.gradle.kts
@@ -29,6 +29,10 @@ kotlin {
} else {
macosX64()
}
+
+ androidNativeArm32()
+ androidNativeArm64()
+
// Uncomment to enable Windows
// mingwX64("windows")
diff --git a/conformance/lib/src/nativeMain/kotlin/pbandk/conformance/io/StdIoSink.kt b/conformance/lib/src/nativeMain/kotlin/pbandk/conformance/io/StdIoSink.kt
index 914cffd3..de8a9be9 100644
--- a/conformance/lib/src/nativeMain/kotlin/pbandk/conformance/io/StdIoSink.kt
+++ b/conformance/lib/src/nativeMain/kotlin/pbandk/conformance/io/StdIoSink.kt
@@ -5,9 +5,12 @@
package pbandk.conformance.io
+import kotlinx.cinterop.ByteVar
import kotlinx.cinterop.CPointer
import kotlinx.cinterop.ExperimentalForeignApi
+import kotlinx.cinterop.UnsafeNumber
import kotlinx.cinterop.addressOf
+import kotlinx.cinterop.convert
import kotlinx.cinterop.usePinned
import kotlinx.io.Buffer
import kotlinx.io.IOException
@@ -37,7 +40,7 @@ internal class StdIoSink(private val file: CPointer) : RawSink {
val allContent = source.readByteArray(byteCount.toInt())
// Copy bytes from that segment into the file.
val bytesWritten = allContent.usePinned { pinned ->
- fwrite(pinned.addressOf(0), 1u, byteCount.toULong(), file).toLong()
+ variantFwrite(pinned.addressOf(0), byteCount.toUInt(), file).toLong()
}
if (bytesWritten < byteCount) {
throw IOException(errno.toString())
@@ -57,4 +60,11 @@ internal class StdIoSink(private val file: CPointer) : RawSink {
throw IOException(errno.toString())
}
}
+
+ @OptIn(UnsafeNumber::class)
+ private fun variantFwrite(
+ source: CPointer,
+ byteCount: UInt,
+ file: CPointer
+ ): UInt = fwrite(source, 1u, byteCount.convert(), file).convert()
}
\ No newline at end of file
diff --git a/conformance/lib/src/nativeMain/kotlin/pbandk/conformance/io/StdIoSource.kt b/conformance/lib/src/nativeMain/kotlin/pbandk/conformance/io/StdIoSource.kt
index cc341e1b..5e53aacb 100644
--- a/conformance/lib/src/nativeMain/kotlin/pbandk/conformance/io/StdIoSource.kt
+++ b/conformance/lib/src/nativeMain/kotlin/pbandk/conformance/io/StdIoSource.kt
@@ -5,9 +5,12 @@
package pbandk.conformance.io
+import kotlinx.cinterop.ByteVar
import kotlinx.cinterop.CPointer
import kotlinx.cinterop.ExperimentalForeignApi
+import kotlinx.cinterop.UnsafeNumber
import kotlinx.cinterop.addressOf
+import kotlinx.cinterop.convert
import kotlinx.cinterop.usePinned
import kotlinx.io.Buffer
import kotlinx.io.IOException
@@ -34,7 +37,7 @@ internal class StdIoSource(private val file: CPointer) : RawSource {
// Copy bytes from the file to the segment.
val fd = fileno(file)
val bytesRead = temporaryBuffer.usePinned { pinned ->
- read(fd, pinned.addressOf(0), byteCount.toULong())
+ variantRead(pinned.addressOf(0), byteCount.toUInt(), fd).toLong()
}
sink.write(temporaryBuffer, startIndex = 0, endIndex = bytesRead.toInt())
@@ -52,4 +55,11 @@ internal class StdIoSource(private val file: CPointer) : RawSource {
closed = true
fclose(file)
}
+
+ @OptIn(UnsafeNumber::class)
+ internal fun variantRead(
+ target: CPointer,
+ byteCount: UInt,
+ fd: Int
+ ): UInt = read(fd, target, byteCount.convert()).convert()
}
\ No newline at end of file
diff --git a/conformance/native/build.gradle.kts b/conformance/native/build.gradle.kts
index 213cec3a..9776df64 100644
--- a/conformance/native/build.gradle.kts
+++ b/conformance/native/build.gradle.kts
@@ -13,6 +13,9 @@ kotlin {
macosX64()
}
+ androidNativeArm32()
+ androidNativeArm64()
+
targets.withType {
binaries {
executable("conformance")
diff --git a/conformance/native/run_android.sh b/conformance/native/run_android.sh
new file mode 100755
index 00000000..5a5b4559
--- /dev/null
+++ b/conformance/native/run_android.sh
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+
+set -e
+set -o pipefail
+
+exec adb shell "/data/local/tmp/conformance.kexe"
\ No newline at end of file
diff --git a/conformance/test-conformance.sh b/conformance/test-conformance.sh
index 354aba5f..0b78a669 100755
--- a/conformance/test-conformance.sh
+++ b/conformance/test-conformance.sh
@@ -31,3 +31,25 @@ if [ "$1" = "macos" ]; then
exit 1
fi
fi
+if [ "$1" = "androidNative" ]; then
+ DEVICE_EXECUTABLE="/data/local/tmp/conformance.kexe"
+ abi_list=$(adb shell getprop ro.product.cpu.abilist)
+ if [[ "$abi_list" == *"arm64-v8a"* ]]; then
+ adb push $DIR/native/build/bin/androidNativeArm64/conformanceReleaseExecutable/conformance.kexe $DEVICE_EXECUTABLE
+ adb shell chmod 777 $DEVICE_EXECUTABLE
+ $CONF_TEST_PATH --enforce_recommended --failure_list $DIR/native/failing_tests.txt $DIR/native/run_android.sh
+ adb shell rm $DEVICE_EXECUTABLE
+ fi
+ if [[ "$abi_list" == *"armeabi"* ]]; then
+ adb push $DIR/native/build/bin/androidNativeArm32/conformanceReleaseExecutable/conformance.kexe $DEVICE_EXECUTABLE
+ adb shell chmod 777 $DEVICE_EXECUTABLE
+ $CONF_TEST_PATH --enforce_recommended --failure_list $DIR/native/failing_tests.txt $DIR/native/run_android.sh
+ adb shell rm $DEVICE_EXECUTABLE
+ fi
+fi
+if [ "$1" = "androidJvm" ]; then
+ DEVICE_APK="/data/local/tmp/conformance.apk"
+ adb push $DIR/android/build/outputs/apk/release/conformance-android-release-unsigned.apk $DEVICE_APK
+ $CONF_TEST_PATH --enforce_recommended --failure_list $DIR/jvm/failing_tests.txt $DIR/android/run.sh
+ adb shell rm $DEVICE_APK
+fi
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 8f4542f5..787b2098 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -32,5 +32,7 @@ include(":conformance:lib")
project(":conformance:lib").name = "conformance-lib"
include(":conformance:jvm")
project(":conformance:jvm").name = "conformance-jvm"
+include(":conformance:android")
+project(":conformance:android").name = "conformance-android"
include(":conformance:native")
project(":conformance:native").name = "conformance-native"