diff options
Diffstat (limited to 'app/build.gradle.kts')
| -rw-r--r-- | app/build.gradle.kts | 89 |
1 files changed, 88 insertions, 1 deletions
diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 36d6038..a7b74cb 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -254,6 +254,29 @@ jacoco { * Compose screens are excluded for the same reason as FeeDreader: they are impractical to * unit-test and including them makes the metric meaningless. * + * They are named one screen file at a time rather than by excluding the whole `ui` package, + * which is what this used to do. That blanket pattern also hid six view models -- plain Kotlin + * classes with real decisions in them, every one measuring 0% and not one of them a Compose + * screen -- behind a justification that only ever applied to the screens. The list below is + * longer, and that is its honest length: each glob names the classes one screen file compiles + * to (its `...Kt` class, its `ComposableSingletons` holder, and the state and action objects + * only that screen constructs). Nothing else under `ui` is excluded. + * + * The action and state objects are excluded on a different ground from the screens, and it is + * worth being explicit so the list does not grow by analogy. They are not hard to execute off a + * device -- `EpisodeActions(play = {}, ...)` constructs fine. They are excluded because every + * line jacoco counts in them is one Kotlin generated: the constructor, `componentN`, `copy`, + * `equals`, `hashCode`, `toString`. There is no statement of this app's own in any of them, so + * measuring them measures the compiler. **That is the whole of the reason**, and it does not + * extend to a data class that gains a method, an `init` block or a default computed from + * another field -- the moment one does, it comes off this list. + * + * Two entries need saying out loud. The BreakJudgingKt glob excludes only the composables in + * BreakJudging.kt; the `BreakJudging` and `BreakJudgingSource` classes beside them stay + * measured. And the EpisodeScreenKt glob takes the tested `stripHtml` out of the measurement + * along with the screen it happens to live in -- a cost of excluding by file, not a reason to + * stop testing it. + * * The rest are framework adapters -- classes whose whole body is a call into ExoPlayer, Media3, * Room, WorkManager or Chaquopy, none of which can execute on the JVM. They were overridden * eight times in a row with `COVERAGE_EXCEPTION`, and the last few were perverse: extracting @@ -267,7 +290,71 @@ jacoco { * logic runs fine against fakes. */ val coverageExclusions = listOf( - "**/ui/**", + // Compose screens, one file at a time. See the note above: `**/ui/**` also hid the view + // models, which are ordinary classes and are measured. + // + // Every Compose file compiles a `ComposableSingletons` holder for its constant lambdas. + // It is generated, there is nothing in it to test, and it belongs to the screen it is + // named after. + "**/ui/ComposableSingletons\$*", + + "**/ui/MainActivity*", + "**/ui/ShareReceiverActivity*", + "**/ui/BreakJudgingKt*", + "**/ui/DripSettingsKt*", + "**/ui/EpisodeDescriptionKt*", + "**/ui/EpisodeOverflowKt*", + "**/ui/EpisodeRowKt*", + "**/ui/EpisodeScreenKt*", + "**/ui/EpisodeTimelineKt*", + "**/ui/EpisodeTransportKt*", + "**/ui/FurnitureSkipSettingsStateKt*", + "**/ui/LibraryScreenKt*", + "**/ui/NowPlayingBarKt*", + "**/ui/PlayerBarKt*", + "**/ui/PlayerMessageKt*", + "**/ui/QueueScreenKt*", + "**/ui/RuleConditionFieldsKt*", + "**/ui/RuleEditScreenKt*", + "**/ui/RulesScreenKt*", + "**/ui/SettingRowsKt*", + "**/ui/SettingsScreenKt*", + "**/ui/ShowSettingsSheetKt*", + "**/ui/SkipServerSettingsStateKt*", + "**/ui/SkipSettingsKt*", + "**/ui/SubscriptionRowKt*", + "**/ui/SubscriptionScreenKt*", + "**/ui/TierSettingKt*", + "**/ui/TranscriptScreenKt*", + + // A screen's own parameter and state objects: data classes of callbacks and already-decided + // values, handed from one composable to another. They decide nothing, they are constructed + // only inside the files above, and the only test that could reach one would call its + // constructor and assert nothing. + // + // Excluded by what they are rather than by which file they sit in. Most are declared inside + // their screen and were already covered by the globs above; these five happen to have files + // of their own, and a line that excluded one and measured the other would be describing the + // author's filing rather than the code. + "**/ui/EpisodeActions*", + "**/ui/EpisodeDetailActions*", + "**/ui/EpisodeDetailState*", + "**/ui/EpisodeHooks*", + "**/ui/EpisodePlayback*", + "**/ui/FurnitureSkipSettings*", + "**/ui/LibraryContent*", + "**/ui/LibraryNav*", + "**/ui/LibraryTopBarActions*", + "**/ui/NowPlayingActions*", + "**/ui/OverflowContent*", + "**/ui/QueueNav*", + "**/ui/QueueRowActions*", + "**/ui/ScreenSource*", + "**/ui/SkipServerSettings*", + "**/ui/SkipSettings*", + "**/ui/SubscriptionNav*", + "**/ui/SubscriptionTopBarActions*", + "**/R.class", "**/R\$*.class", "**/BuildConfig.*", "**/*_Impl*", // ExoPlayer, MediaSession and the browse tree: no JVM equivalent to run against. |
