Release 1.5.0: dependency updates + Kover coverage & CI - #95
Merged
Conversation
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>
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
marked this pull request as draft
June 4, 2026 14:44
- 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>
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
marked this pull request as ready for review
June 8, 2026 08:39
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
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>
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>
jakeeilbeck
approved these changes
Jun 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release 1.5.0 — dependency updates, Kover coverage + CI, and a large test-coverage uplift.
Tooling / CI (Pass 1)
kover.aggregationsettings plugin;koverVerifygate..github/workflows/ci.yml— "Tests & coverage gate" runstest+koverVerifyon PRs intomain.mainrequires the check + 1 approval.Dependency bumps
TOOLBOX_VERSION→ 1.5.0, README version refs synced.Test coverage (Pass 2) — ~1% → ~61% aggregate
createComposeRulev2): AppSnackBar, SegmentedControl, all Lazy* paging overloads (List + Grid), paging state composables, AnimatedVisibility, ComposeExtensions, APIFlowState caching composables.Coverage floor currently 60%.
🤖 Generated with Claude Code