Skip to content

Release 1.5.0: dependency updates + Kover coverage & CI - #95

Merged
projectdelta6 merged 61 commits into
mainfrom
feature/1.5.0-deps-update-and-ci
Jun 8, 2026
Merged

Release 1.5.0: dependency updates + Kover coverage & CI#95
projectdelta6 merged 61 commits into
mainfrom
feature/1.5.0-deps-update-and-ci

Conversation

@projectdelta6

@projectdelta6 projectdelta6 commented Jun 4, 2026

Copy link
Copy Markdown
Collaborator

Release 1.5.0 — dependency updates, Kover coverage + CI, and a large test-coverage uplift.

Draft: Pass 3 (full end-to-end upload pipeline + remaining Compose internals) still to come.

Tooling / CI (Pass 1)

  • Kover aggregated coverage across all modules via the kover.aggregation settings plugin; koverVerify gate.
  • Robolectric for JVM Compose/Android-context tests.
  • .github/workflows/ci.yml — "Tests & coverage gate" runs test + koverVerify on PRs into main.
  • Branch ruleset: main requires the check + 1 approval.

Dependency bumps

  • Kotlin 2.3.21 → 2.4.0, core-ktx 1.18→1.19, Compose BOM …05.00→…05.01, Gradle 9.4.1 → 9.5.0
  • FlexiLogger 2.1.1 → 2.1.3 (fixes Java-24 jvm bytecode; CI runs JDK 24)
  • TOOLBOX_VERSION1.5.0, README version refs synced.

Test coverage (Pass 2) — ~1% → ~61% aggregate

  • Logic/serialization: UiState, APIResult/APIFlowState (+ flow ops), paging predicates, PageData, custom serializers, multipart config/result/network models, Appoly JSON envelopes.
  • Room: full DAO layer (in-memory + constraint flows), converters, entities.
  • Compose UI (Robolectric + createComposeRule v2): AppSnackBar, SegmentedControl, all Lazy* paging overloads (List + Grid), paging state composables, AnimatedVisibility, ComposeExtensions, APIFlowState caching composables.
  • Integration: GenericBaseRepo (Sandwich mapping + flows + RefreshableAPIFlow), ConnectivityMonitor (Robolectric shadows), S3Uploader pipeline + multipart network (MockWebServer), MultipartUploadManager lifecycle, S3UploadWorkManager scheduling, MultipartUploadWorker validation (WorkManager test harness).

Coverage floor currently 60%.

🤖 Generated with Claude Code

Tooling / CI:
- Add Kotlinx Kover 0.9.8 aggregated coverage across all 24 library
  modules, gated in :app (debug variant) with the demo app package
  excluded. Tasks: :app:koverHtmlReportDebug / koverXmlReportDebug /
  koverVerifyDebug. Starting floor minBound(5) — ratchet up once real
  coverage is known.
- Add Robolectric 4.16.1 to the version catalog (ready for future
  Android-context unit tests; not yet wired into a module).
- Add .github/workflows/ci.yml: "Tests & coverage gate" runs tests +
  coverage verify on PRs/pushes into main.

Dependency bumps:
- Kotlin 2.3.21 -> 2.4.0
- androidx core-ktx 1.18.0 -> 1.19.0
- Compose BOM 2026.05.00 -> 2026.05.01
- FlexiLogger 2.1.1 -> 2.1.2
- Gradle wrapper 9.4.1 -> 9.5.0

Bump TOOLBOX_VERSION to 1.5.0 (README version refs synced).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@projectdelta6 projectdelta6 self-assigned this Jun 4, 2026
projectdelta6 and others added 4 commits June 4, 2026 14:53
The pure-Kotlin (java-library) modules resolve flexilogger-*-jvm, whose
classes are compiled to Java 24 (class-file v68). Running tests on JDK 21
threw UnsupportedClassVersionError when loading FlexiLog. Bump the CI JDK
to 24 (still publishing JVM 11 bytecode). Also upload test reports as an
artifact so failures are diagnosable.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Add a custom Kover "aggregated" variant in :app unioning Android-library
  (debug) and pure-JVM (jvm) module coverage. The built-in debug variant
  silently omitted the java-library modules (MockInterceptor family), so
  their tests contributed 0% to the aggregate.
- Pass 1 measures & reports coverage but does not gate on it: most modules
  are untested (~1%) and minBound is integer-only, so no meaningful floor
  is possible yet. CI now runs koverXmlReportAggregated +
  koverHtmlReportAggregated instead of koverVerify. Floor lands in Pass 2.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
add("jvm") only inspects :app's own variants (Android app → debug/release),
so it failed with "Could not find the provided variant 'jvm'".
addWithDependencies("debug"/"jvm", optional=true) reaches into the
kover(project(...)) dependencies and tolerates a variant being absent on a
given project, so the aggregated report unions Android-library debug
coverage with pure-JVM module coverage.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The custom "aggregated" variant failed Gradle variant resolution: a custom
cross-project variant requires every dependency module to declare the same
variant, which they don't. Unifying Android (debug) + pure-JVM (jvm) module
coverage needs either custom variants in all modules or the kover.aggregation
settings plugin — deferred to Pass 2 along with the coverage floor.

Pass 1 ships the built-in koverXmlReportDebug/koverHtmlReportDebug, which
aggregates the Android-library modules. Known limitation documented in
app/build.gradle.kts: the MockInterceptor (java-library) modules aren't in
this report yet.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@projectdelta6
projectdelta6 marked this pull request as draft June 4, 2026 14:44
projectdelta6 and others added 23 commits June 4, 2026 16:18
- Switch to the kover.aggregation settings plugin so coverage aggregates
  across all modules (Android + pure-JVM) into one root report; remove the
  per-module project-plugin wiring and the :app debug-variant aggregation.
- Add unit tests for UiState (predicates), PagingExtensions (LoadState
  predicates + PagingErrorType), APIResult (state/transform extensions) and
  APIFlowState (predicates, accessors, map, cacheSuccessData flow operator),
  and the Appoly JSON response envelopes (GenericResponse/BaseResponse/
  ErrorBody serialization).
- Add kotlinx-coroutines-test for flow-based assertions.

Aggregate coverage 5.0% -> 6.3% (UiState 100%, APIResult 89%).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Tests for BaseRepo-Paging: PageData derived pagination properties
(itemsBefore/itemsAfter/prevPage/nextPage across first/middle/last/single
pages) and GenericPagingSource (load() mapping APIResult Success/Error to
LoadResult.Page/Error, key handling, and getRefreshKey with/without jumping).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The switch to the kover.aggregation settings plugin removed the
:app:koverXmlReportDebug task; CI now runs the root koverXmlReport/
koverHtmlReport. Still report-only — koverVerify + floor added before the
final push (Pass 2 WIP).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2.1.3 ships the *-jvm artifacts as Java 11 bytecode (class-file v55) again,
fixing the UnsupportedClassVersionError that forced CI onto JDK 24. CI can
optionally drop back to JDK 21 now (deferred; JDK 24 still works).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
No-Robolectric pure-logic coverage:
- S3Uploader: StringOrListSerialiser (string|array coercion, incl. real usage
  in GetPreSignedUrlResponse headers), firstNotNullOrBlank (try/skip/fallback,
  exception swallowing), UploadResult/DirectUploadResult.
- ConnectivityMonitor: NetworkTransportType derived properties.
- ComposeExtensions: direction-aware PaddingValues.plus arithmetic.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Establishes the working Robolectric + createComposeRule pattern for JVM
Compose-UI tests: testOptions.unitTests.isIncludeAndroidResources, the
robolectric/compose-ui-test deps, and robolectric.properties (sdk=36).
Tests AppSnackBarColors.get (pure) and the AppSnackBar composable + typed
showSnackbar extension end to end.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- AppSnackBar-UiState: pure snackBarType (UiState -> SnackBarType) mapping.
- PagingExtensions: Robolectric+Compose render tests for the default
  EmptyStateText, LoadingState and ErrorState providers (incl. retry click).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Robolectric+Compose test for the string SegmentedControl overload: renders
all segments and reports the tapped segment, exercising the generic delegate,
SegmentText and the internal layout/gesture state.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Robolectric+Compose tests driving lazyPagingItems / lazyPagingItemsIndexed
with a real Pager of fixed data via collectAsLazyPagingItems.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Robolectric+Compose tests for the LazyGrid lazyPagingItems /
lazyPagingItemsIndexed DSL helpers in a LazyVerticalGrid.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Switch off the deprecated androidx.compose.ui.test.junit4.createComposeRule
to the v2 API (StandardTestDispatcher). Assertions already sync via
waitForIdle/waitUntil, so no behavioural change; clears the deprecation
warning across all Compose-UI tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Robolectric+Compose tests for lazyPagingItemsStates driving the content,
empty and error states of a paged LazyColumn, covering the shared
emptyStateItem/errorStateItem item helpers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Mirror of the LazyList states tests for the LazyVerticalGrid variant.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Robolectric tests for Context.getActivity unwrapping, plus Compose-UI tests
for keyboardAsState, the composable PaddingValues.plus operator and
getActiveActivity.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
In-memory Room DAO tests (Robolectric) covering session/part CRUD, status
updates, recovery queries, atomic claimNextPendingPart, cascade delete,
SessionWithParts relation and cleanup — exercising the Room-generated DAO
implementation. Plus pure tests for the enum type converters.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Pure tests for UploadConstraints (defaults, wifiOnly/powerSaving/lowPriority
presets, negative-delay validation, JSON round-trip) and the
MultipartUploadResult sealed variants.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Covers EmptyArrayAsEmptyMapSerializer (headers:[] -> empty map, object ->
map with joined array values), PresignPartResponse wrapped/unwrapped data
resolution, and InitiateMultipartResponse decoding.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Robolectric+Compose render tests for the standalone, Column- and Row-scoped
ScrollIntoViewAnimatedVisibility overloads (visible/hidden).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Robolectric+Compose tests for lazyPagingItemsIndexedStates,
lazyPagingItems(Indexed)StatesWithNeighbours and lazyPagingItems(Indexed)WithNeighbours
success paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Mirror of the LazyList extra entry-point tests for the LazyVerticalGrid variants.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ops)

Covers updateSessionConstraints, the constraint-violation set/clear flow,
getActiveSessions/getSessionsByStatus, updateSession/deleteSession entity ops,
single-part insert/update/getNextPendingPart, resetUploadingParts, and the
observe-style Flow queries.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a koverVerify rule (minValue=45) to the aggregation settings plugin —
measured aggregate is ~48% after Pass 2. CI now runs koverVerify so the
"Tests & coverage gate" check enforces the floor again.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Robolectric+Compose tests for rememberSuccessDataAsState / rememberSuccessData
/ rememberSuccessListAsState / rememberSuccessList (+ saveable variants),
verifying the last success value is retained across Loading/Error states.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
projectdelta6 and others added 17 commits June 5, 2026 13:31
uploadFileDirect success/failure via MockWebServer (single S3 PUT).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
getConstraintViolatedUploads, resumeConstraintViolatedUpload (success +
not-violated failure), updateConstraints (default update + re-enqueue),
setAllowCellularUploads network-type toggle.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A never-completing Pager keeps refresh in Loading, so lazyPagingItemsStates
renders the supplied refreshLoadingContent (LazyList + LazyGrid).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…lectAsState)

callApiAsRefreshableFlow + RefreshableAPIFlow.stateIn (runTest) and
RefreshableAPIFlow.collectAsState (Compose) round out the data/repo flow APIs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Cover DateHelper.toJsonString/parseJsonDateTime/parseJsonDate round-trips,
toFileString, nowAsUTC, and the format helpers' null handling + round-trips.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- AppolyBaseRepoTest: doAPICallWithBaseResponse success / success-false /
  Failure.Error (real ErrorBody extraction) / Failure.Exception, plus
  extractErrorMessage parse + null-message paths.
- APIFlowStateCacheTest: the four cacheSuccessData operators (plain + transform,
  flow + stateIn), asApiFlowState, and APIFlowState.map's loading/error branches.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add file-not-found, missing-api-url, and onBeforeUpload-Abort branches to the
worker test (all return before any S3 interaction), driven via
TestListenableWorkerBuilder and a singleton config seeded with an aborting
lifecycle callback.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Invoke every lazyPagingItemsStates / IndexedStates / StatesWithNeighbours /
IndexedStatesWithNeighbours overload (emptyText/emptyContent ×
errorText/errorContent, per-item & whole-list) against a populated pager so each
inline delegating body + default loading lambda is exercised. util/paging 36%->48%.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Mirror the LazyList overload sweep for the LazyGrid entry points (States O2-O6,
IndexedStates, StatesWithNeighbours, IndexedStatesWithNeighbours) and cover the
5 deprecated lazyPagingItemsWithStates overloads that delegate to the current API.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- DefaultUploadNotificationProviderTest: channel creation, notification build
  (with/without progress), foreground info, notification id, simple() factory
  (multipart/interfaces 4% -> covered).
- DateHelperExtensionsTest: toUTC, isFuture/isToday/isPassed, daysFromNow,
  toMillis/millisTo round-trips, deviceToUTC/toDeviceZone, Duration helpers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Cover onBeforeUpload/onUploadResumed/onUploadComplete/onUploadPaused/
onProgressUpdate across delegating, callback-throws-swallowed, and
no-callbacks-configured branches.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- EnumSerializersTest: EnumAsInt/String + nullable variants (encode value/null,
  decode value).
- DateSerializersTest: LocalDate/LocalDateTime/ZonedDateTime serializers (+
  nullable) via @serializable holders so the null mark is gated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Invoke every colors() overload (solid + brush variants) and every textStyle()
overload, and render a SegmentedControl with custom brush colors + a
fully-specified text style.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- APIFlowStatePagingExtensionsTest: asPagingData/mapToPagingData (Success/Loading/Error).
- DoPagedAPICallTest: GenericBaseRepo.doPagedAPICall all branches.
- DoNestedPagedAPICallTest: AppolyBaseRepo.doNestedPagedAPICall all branches
  (new test source set for BaseRepo-Paging-AppolyJson).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@projectdelta6
projectdelta6 marked this pull request as ready for review June 8, 2026 08:39
@projectdelta6
projectdelta6 requested a review from jakeeilbeck June 8, 2026 08:39
projectdelta6 and others added 3 commits June 8, 2026 10:01
The koverVerify floor lives in settings.gradle.kts and is now 76% (measured
~77%); the workflow comment still claimed ~45%. Note the accepted hard tail.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Routine tooling refresh. KSP2 uses standalone versioning (decoupled from the
Kotlin version), so this is independent of the Kotlin 2.4.0 bump.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move isIncludeAndroidResources + isReturnDefaultValues out of the 12 per-module
build.gradle.kts files into a single subprojects { plugins.withId("com.android.
library") { ... } } block in the root build. Both flags now apply uniformly to
every Android library module, so the Robolectric/Compose test setup stays
consistent and new modules inherit it automatically. Verified: full `test
koverXmlReport koverVerify` green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jakeeilbeck
jakeeilbeck previously approved these changes Jun 8, 2026
- RefreshableAPIFlowTest: @OptIn(ExperimentalCoroutinesApi) for advanceUntilIdle.
- DateHelperExtrasTest: @Suppress("DEPRECATION") — deliberately exercises our own
  deprecated formatLocalDateTime/parseLocalDateTime (still public API).
- ConnectivityMonitorApplicationTest: @Suppress("DEPRECATION") on the seed helper —
  legacy NetworkInfo/TYPE_WIFI are the only way to drive Robolectric's
  ShadowConnectivityManager active-network lookup.
- MockInterceptorDemoViewModel: drop the unnecessary safe call on the non-null
  OkHttp ResponseBody (response.body.string()).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
projectdelta6 and others added 2 commits June 8, 2026 11:18
The Kover aggregation settings plugin registers koverHtmlReport / koverXmlReport
/ koverVerify on the root project but doesn't auto-depend on the per-module
`test` tasks, so a standalone `./gradlew koverHtmlReport` reported "no coverage
information was found". Depend on every module's `test` so the reports always run
against fresh coverage. CI already passes `test` explicitly (Gradle de-dupes), so
this only fixes local standalone report runs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@projectdelta6
projectdelta6 merged commit acae87e into main Jun 8, 2026
1 check passed
@projectdelta6
projectdelta6 deleted the feature/1.5.0-deps-update-and-ci branch June 8, 2026 10:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants