fix(commons): make commonTest compile for iOS targets

The commons commonTest source set is shared across all KMP targets,
including the iosArm64/iosSimulatorArm64 spike, but several tests still
reached for JVM-only APIs that don't resolve on Kotlin/Native:

- JUnit (`org.junit.*`, `junit.framework.TestCase`) → kotlin.test, with
  message arguments moved from first (JUnit) to last (kotlin.test).
- `assertArrayEquals` → `assertContentEquals`.
- `@JvmStatic` on the `android.util.Log` test stub → removed (it only
  affects JVM bytecode; companion calls work without it).
- `seg.javaClass.simpleName` → `seg::class.simpleName!!`.
- A test function name containing `()` (illegal on Native) → renamed.
- `String(CharArray, offset, count)` → `CharArray.concatToString`.

CliffDetectorTest exercises `computeStalledSpeakers`/`defaultCliffBackoffMs`,
which live in the jvmAndroid-only NestViewModel and are invisible to iOS,
so it moves to jvmTest alongside NestViewModelTest.
This commit is contained in:
Claude
2026-06-09 19:26:04 +00:00
parent 3dfe418150
commit fc4f7a03fc
13 changed files with 94 additions and 102 deletions
@@ -22,13 +22,11 @@ package android.util
class Log {
companion object {
@JvmStatic
fun isLoggable(
tag: String?,
msg: Int?,
): Boolean = true
@JvmStatic
fun d(
tag: String?,
msg: String?,
@@ -37,7 +35,6 @@ class Log {
return 0
}
@JvmStatic
fun i(
tag: String?,
msg: String?,
@@ -46,7 +43,6 @@ class Log {
return 0
}
@JvmStatic
fun w(
tag: String?,
msg: String?,
@@ -55,7 +51,6 @@ class Log {
return 0
}
@JvmStatic
fun w(
tag: String?,
msg: String?,
@@ -66,7 +61,6 @@ class Log {
return 0
}
@JvmStatic
fun e(
tag: String?,
msg: String?,
@@ -75,7 +69,6 @@ class Log {
return 0
}
@JvmStatic
fun e(
tag: String?,
msg: String?,
@@ -21,22 +21,22 @@
package com.vitorpamplona.amethyst.commons
import com.vitorpamplona.amethyst.commons.blurhash.Base83
import org.junit.Assert.assertEquals
import org.junit.Test
import kotlin.test.Test
import kotlin.test.assertEquals
class Base83Test {
@Test
fun testEncodeDecode() {
for (i in 0..820000) {
assertEquals("$i encode decode", i, Base83.decode(Base83.encode(i.toLong())))
assertEquals(i, Base83.decode(Base83.encode(i.toLong())), "$i encode decode")
}
}
@Test
fun testSingleDigits() {
for (i in 0..82) {
val expected: String = String(Base83.ALPHABET, i, 1)
assertEquals("$i encodes", expected, Base83.encode(i.toLong(), 1))
val expected: String = Base83.ALPHABET.concatToString(i, i + 1)
assertEquals(expected, Base83.encode(i.toLong(), 1), "$i encodes")
}
}
@@ -21,22 +21,22 @@
package com.vitorpamplona.amethyst.commons
import com.vitorpamplona.amethyst.commons.blurhash.SRGB
import org.junit.Assert.assertEquals
import org.junit.Test
import kotlin.math.round
import kotlin.test.Test
import kotlin.test.assertEquals
class SRGBTest {
@Test
fun testEncodeDecode() {
for (i in 0..255) {
assertEquals("$i encode decode", i, SRGB.linearToSrgb(SRGB.srgbToLinear(i)))
assertEquals(i, SRGB.linearToSrgb(SRGB.srgbToLinear(i)), "$i encode decode")
}
for (i in 0..100) {
val srgb = SRGB.linearToSrgb(i / 100.0f)
val linear = round(SRGB.srgbToLinear(srgb) * 100).toInt()
assertEquals("$i decode encode", i, linear)
assertEquals(i, linear, "$i decode encode")
}
}
}
@@ -22,12 +22,12 @@ package com.vitorpamplona.amethyst.commons
import com.vitorpamplona.amethyst.commons.thumbhash.ThumbHashDecoder
import com.vitorpamplona.amethyst.commons.thumbhash.ThumbHashEncoder
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Test
import kotlin.math.abs
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertNull
import kotlin.test.assertTrue
class ThumbHashTest {
@Test
@@ -37,20 +37,20 @@ class ThumbHashTest {
val pixels = IntArray(w * h) { 0xFFFF8040.toInt() } // opaque warm orange
val hashBytes = ThumbHashEncoder.encode(pixels, w, h)
assertTrue("hash should have at least header bytes", hashBytes.size >= 5)
assertTrue(hashBytes.size >= 5, "hash should have at least header bytes")
val decoded = ThumbHashDecoder.decode(hashBytes)
assertNotNull(decoded)
decoded!!
assertTrue("decoded width should be positive", decoded.width > 0)
assertTrue("decoded height should be positive", decoded.height > 0)
assertTrue(decoded.width > 0, "decoded width should be positive")
assertTrue(decoded.height > 0, "decoded height should be positive")
val originalRatio = w.toFloat() / h.toFloat()
val decodedRatio = decoded.width.toFloat() / decoded.height.toFloat()
// ThumbHash loses some precision, but landscape vs portrait should be preserved.
assertTrue(
"decoded ratio ($decodedRatio) should be on the same side of 1 as original ($originalRatio)",
(originalRatio > 1f) == (decodedRatio > 1f) || originalRatio == decodedRatio,
"decoded ratio ($decodedRatio) should be on the same side of 1 as original ($originalRatio)",
)
}
@@ -69,8 +69,8 @@ class ThumbHashTest {
}
val encoded = ThumbHashEncoder.encodeToBase64(pixels, w, h)
assertTrue("base64 string should be non-empty", encoded.isNotEmpty())
assertTrue("base64 string should not contain padding", !encoded.contains('='))
assertTrue(encoded.isNotEmpty(), "base64 string should be non-empty")
assertTrue(!encoded.contains('='), "base64 string should not contain padding")
val viaBase64 = ThumbHashDecoder.decode(encoded)
assertNotNull(viaBase64)
@@ -80,8 +80,8 @@ class ThumbHashTest {
assertNotNull(viaBytes)
viaBytes!!
assertEquals("base64 path and raw path should agree on width", viaBytes.width, viaBase64.width)
assertEquals("base64 path and raw path should agree on height", viaBytes.height, viaBase64.height)
assertEquals(viaBytes.width, viaBase64.width, "base64 path and raw path should agree on width")
assertEquals(viaBytes.height, viaBase64.height, "base64 path and raw path should agree on height")
}
@Test
@@ -101,7 +101,7 @@ class ThumbHashTest {
decoded!!
for (p in decoded.pixels) {
val a = (p ushr 24) and 0xff
assertEquals("alpha should be 255 for opaque encode", 255, a)
assertEquals(255, a, "alpha should be 255 for opaque encode")
}
}
@@ -120,7 +120,7 @@ class ThumbHashTest {
val a = (p ushr 24) and 0xff
if (a > maxAlpha) maxAlpha = a
}
assertTrue("max alpha of all-transparent decode should be low; got $maxAlpha", maxAlpha <= 16)
assertTrue(maxAlpha <= 16, "max alpha of all-transparent decode should be low; got $maxAlpha")
}
@Test
@@ -150,9 +150,9 @@ class ThumbHashTest {
val avgB = sumB / count
// ThumbHash quantisation allows a handful of codepoints of drift.
assertTrue("avg R drift: expected ${target[0]}, got $avgR", abs(avgR - target[0]) < 8)
assertTrue("avg G drift: expected ${target[1]}, got $avgG", abs(avgG - target[1]) < 8)
assertTrue("avg B drift: expected ${target[2]}, got $avgB", abs(avgB - target[2]) < 8)
assertTrue(abs(avgR - target[0]) < 8, "avg R drift: expected ${target[0]}, got $avgR")
assertTrue(abs(avgG - target[1]) < 8, "avg G drift: expected ${target[1]}, got $avgG")
assertTrue(abs(avgB - target[2]) < 8, "avg B drift: expected ${target[2]}, got $avgB")
}
@Test
@@ -163,7 +163,7 @@ class ThumbHashTest {
val hash = ThumbHashEncoder.encode(pixels, w, h)
val ratio = ThumbHashDecoder.aspectRatio(hash)
assertNotNull(ratio)
assertTrue("landscape ratio should be > 1, got $ratio", ratio!! > 1f)
assertTrue(ratio!! > 1f, "landscape ratio should be > 1, got $ratio")
}
@Test
@@ -174,11 +174,11 @@ class ThumbHashTest {
val hash = ThumbHashEncoder.encode(pixels, w, h)
val ratio = ThumbHashDecoder.aspectRatio(hash)
assertNotNull(ratio)
assertTrue("portrait ratio should be < 1, got $ratio", ratio!! < 1f)
assertTrue(ratio!! < 1f, "portrait ratio should be < 1, got $ratio")
}
@Test
fun `repeated decodes produce identical output (cosine cache determinism)`() {
fun `repeated decodes produce identical output - cosine cache determinism`() {
val w = 40
val h = 30
val pixels =
@@ -222,8 +222,8 @@ class ThumbHashTest {
// Chop off half the AC payload.
val truncated = fullHash.copyOfRange(0, 5 + (fullHash.size - 5) / 4)
assertNull(
"hash with insufficient AC bytes should be rejected",
ThumbHashDecoder.decode(truncated),
"hash with insufficient AC bytes should be rejected",
)
}
@@ -239,13 +239,13 @@ class ThumbHashTest {
assertNotNull(decoded)
decoded!!
assertTrue(
"expected output to fit in 32x32, got ${decoded.width}x${decoded.height}",
decoded.width in 1..32 && decoded.height in 1..32,
"expected output to fit in 32x32, got ${decoded.width}x${decoded.height}",
)
assertEquals(
"pixel buffer size must match dimensions",
decoded.width * decoded.height,
decoded.pixels.size,
"pixel buffer size must match dimensions",
)
}
}
@@ -20,9 +20,9 @@
*/
package com.vitorpamplona.amethyst.commons.emojicoder
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
class EmojiCoderTest {
companion object {
@@ -68,7 +68,7 @@ class EmojiCoderTest {
val encoded = EmojiCoder.encode(emoji, sentence)
val decoded = EmojiCoder.decode(encoded)
assertEquals(sentence, decoded)
assertTrue("Failed sentence for emoji $emoji with sentence `$sentence`: `$encoded`", EmojiCoder.isCoded(encoded))
assertTrue(EmojiCoder.isCoded(encoded), "Failed sentence for emoji $emoji with sentence `$sentence`: `$encoded`")
}
}
}
@@ -21,8 +21,8 @@
package com.vitorpamplona.amethyst.commons.model
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
import org.junit.Assert.assertEquals
import org.junit.Test
import kotlin.test.Test
import kotlin.test.assertEquals
/**
* Lock in the descending-by-usage ordering and equal-count preservation of
@@ -23,12 +23,12 @@ package com.vitorpamplona.amethyst.commons.model.nip05DnsIdentifiers.namecoin
import com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin.ElectrumxServer
import com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin.NamecoinBackend
import com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin.NamecoinCoreRpcConfig
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Test
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNotNull
import kotlin.test.assertNull
import kotlin.test.assertTrue
class NamecoinSettingsTest {
// ── Server string parsing ──────────────────────────────────────────
@@ -21,10 +21,10 @@
package com.vitorpamplona.amethyst.commons.model.nip30CustomEmojis
import com.vitorpamplona.quartz.nip30CustomEmoji.EmojiUrlTag
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
class OwnedEmojiPackTest {
private val publicEmoji = EmojiUrlTag("public_one", "https://example.com/public.png")
@@ -21,9 +21,9 @@
package com.vitorpamplona.amethyst.commons.richtext
import com.vitorpamplona.amethyst.commons.model.EmptyTagList
import org.junit.Assert.assertTrue
import org.junit.Test
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
class RichTextParserMultibyteTest {
@Test
@@ -42,20 +42,20 @@ class RichTextParserMultibyteTest {
// user@example.com should be EmailSegment
assertTrue(
"user@example.com should be EmailSegment",
allSegments.any { it is EmailSegment && it.segmentText == "user@example.com" },
"user@example.com should be EmailSegment",
)
// user@example.com should NOT be a LinkSegment
assertTrue(
"user@example.com should not be a LinkSegment",
allSegments.none { it is LinkSegment && it.segmentText == "user@example.com" },
"user@example.com should not be a LinkSegment",
)
// user@example.com should not be in urlSet
assertTrue(
"user@example.com should not be in urlSet",
!state.urlSet.withScheme.contains("user@example.com") && !state.urlSet.withoutScheme.contains("user@example.com"),
"user@example.com should not be in urlSet",
)
}
@@ -145,8 +145,8 @@ class RichTextParserMultibyteTest {
val state = RichTextParser().parseText(text, EmptyTagList, null)
val allSegments = state.paragraphs.flatMap { it.words }
assertTrue(
"user@example.com should be EmailSegment",
allSegments.any { it is EmailSegment && it.segmentText == "user@example.com" },
"user@example.com should be EmailSegment",
)
}
@@ -158,11 +158,11 @@ class RichTextParserMultibyteTest {
val allSegments = state.paragraphs.flatMap { it.words }
val urlSegments = allSegments.filterIsInstance<SchemelessUrlSegment>()
assertTrue("Should have SchemelessUrlSegment", urlSegments.isNotEmpty())
assertTrue("URL should be example.com", urlSegments.any { it.segmentText == "example.com" })
assertTrue(urlSegments.isNotEmpty(), "Should have SchemelessUrlSegment")
assertTrue(urlSegments.any { it.segmentText == "example.com" }, "URL should be example.com")
val textSegments = allSegments.filterIsInstance<RegularTextSegment>()
assertTrue("Should have prefix ああ", textSegments.any { it.segmentText == "ああ" })
assertTrue(textSegments.any { it.segmentText == "ああ" }, "Should have prefix ああ")
}
@Test
@@ -173,11 +173,11 @@ class RichTextParserMultibyteTest {
val allSegments = state.paragraphs.flatMap { it.words }
val urlSegments = allSegments.filterIsInstance<SchemelessUrlSegment>()
assertTrue("Should have SchemelessUrlSegment", urlSegments.isNotEmpty())
assertTrue("URL should be example.com", urlSegments.any { it.segmentText == "example.com" })
assertTrue(urlSegments.isNotEmpty(), "Should have SchemelessUrlSegment")
assertTrue(urlSegments.any { it.segmentText == "example.com" }, "URL should be example.com")
val textSegments = allSegments.filterIsInstance<RegularTextSegment>()
assertTrue("Should have suffix ああ", textSegments.any { it.segmentText == "ああ" })
assertTrue(textSegments.any { it.segmentText == "ああ" }, "Should have suffix ああ")
}
@Test
@@ -188,12 +188,12 @@ class RichTextParserMultibyteTest {
val allSegments = state.paragraphs.flatMap { it.words }
val emailSegment = allSegments.filterIsInstance<EmailSegment>()
assertTrue("Should have EmailSegment", emailSegment.isNotEmpty())
assertTrue("Email should be user@example.com", emailSegment.any { it.segmentText == "user@example.com" })
assertTrue(emailSegment.isNotEmpty(), "Should have EmailSegment")
assertTrue(emailSegment.any { it.segmentText == "user@example.com" }, "Email should be user@example.com")
val textSegments = allSegments.filterIsInstance<RegularTextSegment>()
assertTrue("Should have prefix ほむほむ", textSegments.any { it.segmentText == "ほむほむ" })
assertTrue("Should have suffix ほげほげ", textSegments.any { it.segmentText == "ほげほげ" })
assertTrue(textSegments.any { it.segmentText == "ほむほむ" }, "Should have prefix ほむほむ")
assertTrue(textSegments.any { it.segmentText == "ほげほげ" }, "Should have suffix ほげほげ")
}
@Test
@@ -204,10 +204,10 @@ class RichTextParserMultibyteTest {
val allSegments = state.paragraphs.flatMap { it.words }
val emailSegment = allSegments.filterIsInstance<EmailSegment>()
assertTrue("Should have EmailSegment", emailSegment.isNotEmpty())
assertTrue("Email should be user@example.com", emailSegment.any { it.segmentText == "user@example.com" })
assertTrue(emailSegment.isNotEmpty(), "Should have EmailSegment")
assertTrue(emailSegment.any { it.segmentText == "user@example.com" }, "Email should be user@example.com")
val textSegments = allSegments.filterIsInstance<RegularTextSegment>()
assertTrue("Should have suffix ふがふが", textSegments.any { it.segmentText == "ふがふが" })
assertTrue(textSegments.any { it.segmentText == "ふがふが" }, "Should have suffix ふがふが")
}
}
File diff suppressed because one or more lines are too long
@@ -30,10 +30,10 @@ import com.vitorpamplona.quartz.nip01Core.core.Address
import com.vitorpamplona.quartz.nip01Core.core.Event
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Test
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNull
import kotlin.test.assertTrue
class ReplyContextTest {
private val parentEventId = "b857504288c18a15950dd05b9e8772c62ca6289d5aac373c0a8ee5b132e94e7c"
@@ -20,9 +20,9 @@
*/
package com.vitorpamplona.amethyst.commons.util
import org.junit.Assert.assertArrayEquals
import org.junit.Assert.assertEquals
import org.junit.Test
import kotlin.test.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
class CodePointsTest {
// ---- codePointCharCount ----
@@ -44,30 +44,30 @@ class CodePointsTest {
@Test
fun toCharsRoundTripsAscii() {
assertArrayEquals(charArrayOf('A'), codePointToChars(0x0041))
assertContentEquals(charArrayOf('A'), codePointToChars(0x0041))
}
@Test
fun toCharsRoundTripsLastBmp() {
assertArrayEquals(charArrayOf('￿'), codePointToChars(0xFFFF))
assertContentEquals(charArrayOf('￿'), codePointToChars(0xFFFF))
}
@Test
fun toCharsProducesSurrogatePairForGrinningFace() {
// U+1F600 (😀) is encoded as the surrogate pair (0xD83D, 0xDE00).
assertArrayEquals(charArrayOf('\uD83D', '\uDE00'), codePointToChars(0x1F600))
assertContentEquals(charArrayOf('\uD83D', '\uDE00'), codePointToChars(0x1F600))
}
@Test
fun toCharsProducesSurrogatePairForFirstSupplementary() {
// U+10000 -> (0xD800, 0xDC00).
assertArrayEquals(charArrayOf('\uD800', '\uDC00'), codePointToChars(0x10000))
assertContentEquals(charArrayOf('\uD800', '\uDC00'), codePointToChars(0x10000))
}
@Test
fun toCharsProducesSurrogatePairForLastCodePoint() {
// U+10FFFF -> (0xDBFF, 0xDFFF).
assertArrayEquals(charArrayOf('\uDBFF', '\uDFFF'), codePointToChars(0x10FFFF))
assertContentEquals(charArrayOf('\uDBFF', '\uDFFF'), codePointToChars(0x10FFFF))
}
// ---- String.codePointAtKmp ----
@@ -141,11 +141,11 @@ class CodePointsTest {
for (cp in samples) {
val chars = codePointToChars(cp)
val asString = chars.concatToString()
assertEquals("round-trip code point U+${cp.toString(16).uppercase()}", cp, asString.codePointAtKmp(0))
assertEquals(cp, asString.codePointAtKmp(0), "round-trip code point U+${cp.toString(16).uppercase()}")
assertEquals(
"char count for U+${cp.toString(16).uppercase()}",
chars.size,
codePointCharCount(cp),
"char count for U+${cp.toString(16).uppercase()}",
)
}
}