summaryrefslogtreecommitdiff
path: root/app/build.gradle.kts
diff options
context:
space:
mode:
Diffstat (limited to 'app/build.gradle.kts')
-rw-r--r--app/build.gradle.kts89
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.