diff --git a/app/src/main/java/com/github/damontecres/wholphin/services/UpdateChecker.kt b/app/src/main/java/com/github/damontecres/wholphin/services/UpdateChecker.kt index 3b53138d..706285f2 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/services/UpdateChecker.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/services/UpdateChecker.kt @@ -77,7 +77,8 @@ class UpdateChecker ): JsonObject? = releases .firstOrNull { release -> - Version.tryFromString(release.jsonObject["name"]?.jsonPrimitive?.contentOrNull) == version + val candidate = Version.tryFromString(release.jsonObject["name"]?.jsonPrimitive?.contentOrNull) + candidate != null && !candidate.isGreaterThan(version) && !version.isGreaterThan(candidate) }?.jsonObject /** diff --git a/app/src/test/java/com/github/damontecres/wholphin/test/TestUpdateChecker.kt b/app/src/test/java/com/github/damontecres/wholphin/test/TestUpdateChecker.kt index f0f51931..2e84e2ca 100644 --- a/app/src/test/java/com/github/damontecres/wholphin/test/TestUpdateChecker.kt +++ b/app/src/test/java/com/github/damontecres/wholphin/test/TestUpdateChecker.kt @@ -7,6 +7,7 @@ import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonPrimitive @@ -26,6 +27,7 @@ class TestUpdateChecker { private val forgejoLatest: JsonObject by lazy { read("forgejo_release_latest.json") } private val forgejoAssets: JsonArray by lazy { forgejoLatest["assets"]!!.jsonArray } private val forgejoReleases: JsonArray by lazy { readElement("forgejo_releases.json").jsonArray } + private val suffixedAssets: JsonArray by lazy { read("forgejo_release_suffixed.json")["assets"]!!.jsonArray } private fun readElement(filename: String): JsonElement { val resource = javaClass.classLoader?.getResource(filename) @@ -113,12 +115,58 @@ class TestUpdateChecker { Assert.assertNull(getDownloadUrl(forgejoAssets, true, listOf("arm64-v8a"))) } + @Test + fun `Choose debug ABI before universal and fall back for missing ABI`() { + for ((abis, name) in listOf( + listOf("arm64-v8a") to "Wolfskin-debug-arm64-v8a.apk", + listOf("unknown") to "Wolfskin-debug.apk", + emptyList() to "Wolfskin-debug.apk", + )) { + Assert.assertEquals(forgejoDownload(name), getDownloadUrl(suffixedAssets, true, abis)) + } + } + + @Test + fun `Choose release suffixed ABI before universal and unsuffixed assets`() { + val assets = JsonArray(forgejoAssets + suffixedAssets) + for ((abis, name) in listOf( + listOf("arm64-v8a") to "Wolfskin-release-arm64-v8a.apk", + listOf("armeabi-v7a") to "Wolfskin-release.apk", + emptyList() to "Wolfskin-release.apk", + )) { + Assert.assertEquals(forgejoDownload(name), getDownloadUrl(assets, false, abis)) + } + } + + @Test + fun `Release and debug assets do not cross build types`() { + val debugAssets = JsonArray(suffixedAssets.filter { it.jsonObject["name"]!!.jsonPrimitive.content.contains("-debug") }) + val releaseAssets = JsonArray(suffixedAssets.filter { it.jsonObject["name"]!!.jsonPrimitive.content.contains("-release") }) + Assert.assertNull(getDownloadUrl(debugAssets, false, listOf("arm64-v8a"))) + Assert.assertNull(getDownloadUrl(releaseAssets, true, listOf("arm64-v8a"))) + } + @Test fun `Find installed version in release list`() { val release = UpdateChecker.findReleaseByVersion(forgejoReleases, Version.fromString("1.0.9-2-g3094fc8c")) Assert.assertEquals("v1.0.9-2-g3094fc8c", release?.get("name")?.jsonPrimitive?.content) } + @Test + fun `Find release with different hash abbreviation length`() { + val release = UpdateChecker.findReleaseByVersion(forgejoReleases, Version.fromString("1.0.9-2-g3094fc8")) + Assert.assertEquals("v1.0.9-2-g3094fc8c", release?.get("name")?.jsonPrimitive?.content) + } + + @Test + fun `Find release with absent or zero commit count`() { + val release = UpdateChecker.findReleaseByVersion(forgejoReleases, Version.fromString("1.0.10")) + Assert.assertEquals("v1.0.10-0-gfeedbee", release?.get("name")?.jsonPrimitive?.content) + val plainRelease = JsonObject(forgejoReleases.first().jsonObject + ("name" to JsonPrimitive("v1.0.10"))) + val plainReleases = JsonArray(listOf(plainRelease)) + Assert.assertEquals(plainReleases.first(), UpdateChecker.findReleaseByVersion(plainReleases, Version.fromString("1.0.10-0-gfeedbee"))) + } + @Test fun `Find no release for version missing from list`() { Assert.assertNull(UpdateChecker.findReleaseByVersion(forgejoReleases, Version.fromString("1.0.9-3-gffffff"))) diff --git a/app/src/test/resources/forgejo_release_suffixed.json b/app/src/test/resources/forgejo_release_suffixed.json new file mode 100644 index 00000000..c2155081 --- /dev/null +++ b/app/src/test/resources/forgejo_release_suffixed.json @@ -0,0 +1,24 @@ +{ + "name": "v1.0.9-2-g3094fc8c", + "tag_name": "pwolfskin-v1.0.9-2-g3094fc8c", + "published_at": "2026-10-20T09:05:00Z", + "body": "Wolfskin release and debug builds", + "assets": [ + { + "name": "Wolfskin-debug.apk", + "browser_download_url": "https://git.justinvisser.org/justinzeus/wolfskin/releases/download/pwolfskin-v1.0.9-2-g3094fc8c/Wolfskin-debug.apk" + }, + { + "name": "Wolfskin-release.apk", + "browser_download_url": "https://git.justinvisser.org/justinzeus/wolfskin/releases/download/pwolfskin-v1.0.9-2-g3094fc8c/Wolfskin-release.apk" + }, + { + "name": "Wolfskin-debug-arm64-v8a.apk", + "browser_download_url": "https://git.justinvisser.org/justinzeus/wolfskin/releases/download/pwolfskin-v1.0.9-2-g3094fc8c/Wolfskin-debug-arm64-v8a.apk" + }, + { + "name": "Wolfskin-release-arm64-v8a.apk", + "browser_download_url": "https://git.justinvisser.org/justinzeus/wolfskin/releases/download/pwolfskin-v1.0.9-2-g3094fc8c/Wolfskin-release-arm64-v8a.apk" + } + ] +} diff --git a/docker/README.md b/docker/README.md index 353a716f..f1a1b7d0 100644 --- a/docker/README.md +++ b/docker/README.md @@ -17,6 +17,11 @@ use the catalog's exact Wholphin extension version (currently `0.2.4`). Do not place local extension AARs in `app/libs`: upstream prefers them over the pinned GitHub Packages dependencies. +Upload release assets renamed to `Wolfskin.apk` / `Wolfskin-.apk` for the +in-app updater. Gradle outputs +`Wholphin-default-release--[-].apk`; strip the +flavor, version, and code as well as replacing the prefix. + Upstream enables JVM unit tests only for debug variants; there is no `testDefaultReleaseUnitTest` task. `make test` uses the closest default-flavor task without changing upstream's test configuration.