Files
Look4Sat-mckero/core/domain/build.gradle.kts
T
mckero 1a3c94f1e0 refactor(domain): make core:domain multiplatform so iOS can reuse it
The orbital maths, the satellite models and the repository contracts sat in a Kotlin/JVM
module, so an iOS target could not share a single line of them: java.lang.String.format,
InputStream, System.currentTimeMillis, java.util.Locale and org.json are all JVM-only, and
the tests that covered them used JUnit4. core:domain now declares jvm, iosArm64 and
iosSimulatorArm64 targets, its sources moved to commonMain/commonTest, and the JVM-only
pieces were replaced with multiplatform equivalents: java.lang.String.format by a shared
printf implementation, System.currentTimeMillis by kotlin.time.Clock, InputStream by
ByteArray, org.json by kotlinx-serialization, Locale by nothing at all. Tests that read
classpath resources (javaClass.classLoader) moved to jvmTest, because that is JVM-only
behaviour rather than a JVM-only API.

Auditing the migration against the old module turned up four things that were wrong rather
than merely ported:

- java.lang.String.format rounds the shortest decimal representation of a double half-up,
  not the binary value: "%.3f" of 0.5005 is "0.501", because the stored double is
  0.50049999999999994493. The shared implementation scaled in binary first and printed
  "0.500", which would have changed APRS position packets and the Wavelog frequency fields
  against the released Android app. It now takes the digits from the decimal representation
  and rounds them with integer arithmetic, and jvmTest compares it against
  String.format(Locale.ROOT, ...) over 40 000 sampled doubles plus the boundary cases, while
  commonTest pins literals so the iOS run checks the same digits.

- The queue mutators lost the kotlin.jvm.Synchronized monitor each of them had. It is not a
  JVM-only annotation - it is an optional expectation, so it still compiles in common code -
  but the stdlib deprecated it for common use in 1.8 and made it an error in 2.1. The monitor
  is a platform actual now: the JVM keeps the real monitor, since Compose and the upload
  coroutine both reach the queue there, and iOS carries a documented placeholder until the
  iOS side has a second thread to protect against.

- 107 assertions in DataParserTest and QthConverterTest were bare kotlin.assert calls, which
  a build without -ea skips silently: they are assertTrue now, so the iOS run cannot pass
  vacuously. The three Locale.setDefault cases (ar-EG, bn-BD, fa-IR) that used to guard APRS
  output against Eastern Arabic digits moved to jvmTest instead of being deleted with the
  Locale dependency - APRS-IS is an ASCII protocol, and Locale.setDefault does not exist on
  iOS.

- @Volatile on the LoTW name cache would not have compiled for iOS either: kotlin.jvm's
  variant is an error in common code since 2.1. kotlin.concurrent.Volatile is the
  multiplatform annotation, and it is the stronger form: it takes effect on Kotlin/Native
  rather than being ignored.

A second audit pass over the files the first one could not reach - the HTTP client, the
parsers, the queue and the injection - found three more:

- OkHttpHttpClient built its Request outside the try, so a URL OkHttp refuses to parse left
  postQso/testToken/getStation as an exception, and neither caller catches one. The client it
  replaced reported HTTP -1 and let the caller treat it as a failure; building the request
  inside the try restores that, and a transport failure reports -1 again rather than 0.

- WavelogQueue's readers were stricter than the org.json ones they replaced. A timestamp
  stored as 1234.0 (or "1234.0") read back as 0L instead of 1234 - a QSO uploaded as 1970 -
  and a field holding an object or array threw the whole list away instead of falling back.
  The readers coerce decimals, keep the old defaults and no longer throw, matching optLong,
  optInt, optString and optBoolean.

- The ADIF dates went through the JVM default locale before, so a device set to Arabic wrote
  Eastern Arabic digits into the QSO date. The shared formatter only ever produces ASCII,
  which the locale cases in AprsPacketDefaultLocaleTest pin down.

Verified locally with ./gradlew jvmTest (343 tests, 0 failures) and the multiplatform gate
in check-multiplatform.sh, which now also refuses JVM-only stdlib APIs that resolve in common
code but fail to compile for iOS: @Synchronized, kotlin.jvm.Volatile, synchronized(),
toUpperCase/toLowerCase/capitalize, BigDecimal. The iOS targets themselves need the macOS
runner in .github/workflows/ios-kmp.yml.
2026-09-27 08:55:49 +01:00

4 lines
64 B
Kotlin

plugins {
alias(libs.plugins.convention.coreDomainPlugin)
}