Swapping the navigation rail and the bottom bar passes the whole suite, and Medium is in no test at all #173

Closed
opened 2026-09-02 02:15:06 +00:00 by JMR-dev · 0 comments
JMR-dev commented 2026-09-02 02:15:06 +00:00 (Migrated from github.com)

The adaptive shell: both branches run, nothing checks which one rendered

MainActivity.kt:113-149 (useRail, the NavigationRail-in-a-Row vs
Scaffold(bottomBar = { NavigationBar { … } })) and :154-159 (Content).

This is an assertion gap, not a coverage gap, and that is the point. JaCoCo is green on the
layout branches — AppRootRestorationTest drives Compact and Expanded — but
grep -rn 'NavigationRail\|NavigationBar\|useRail' app/src/test app/src/androidTest returns
nothing. Swapping the two bodies passes the entire suite. This is the shape CLAUDE.md records
from the mutation review: green is not evidence.

Two more facts in the same place:

  • WindowWidthSizeClass.Medium appears in no test at all. The code folds it into the rail
    branch via != Compact; changing that to == Expanded would silently break tablet and foldable
    layouts with nothing failing.
  • Content is 0% (MainActivityKt.Content, 6 lines, 3 of 3 branches). Every existing test
    passes a stub content lambda, so the CONVERT→ConverterScreen / JOIN→JoinScreen mapping is
    never rendered by anything.

This is what AppRoot's own KDoc (:85-96) says the shell exists for: "it has to lay out properly
at every width"
, citing targetSdk 37's forced resizing.

Feasibility: checked, and it works

Rendering AppRoot with its default content reaches ConverterScreen's
viewModel: ConversionViewModel = viewModel(), which needs a ViewModelStoreOwner — and every
existing test uses createComposeRule, which supplies none.

Measured on main before filing: createAndroidComposeRule<ComponentActivity>() works under
Robolectric here. A spike rendering AppRoot(WindowWidthSizeClass.Compact) with default content
found converter.chooseFile, clicked the Join tab, found join.chooseFiles, and passed in 10.4s —
then went red when Content's two arms were transposed. So Content is in scope; no seam is
needed.

Two things make it work, both already true: both ViewModels are
@JvmOverloads constructor(app: Application, …) with defaults, so AndroidViewModelFactory builds
them; and app/build.gradle.kts states that ui-test-manifest's debugImplementation entry
already supplies the ComponentActivity to the merged manifest the unit tests build against.

Use the v2 rule (androidx.compose.ui.test.junit4.v2.createAndroidComposeRule) to match the
repo's existing v2 createComposeRule; the non-v2 one compiles with a deprecation warning. The
test needs installTestWorkManager and the ConversionDependencies fakes in @Before, as
ScreenWiringTest does.

Acceptance: three mutations, all must go red

  1. Swap the NavigationRail and NavigationBar bodies.
  2. Change widthSizeClass != WindowWidthSizeClass.Compact to == WindowWidthSizeClass.Expanded
    (this is what the Medium case is for).
  3. Transpose Content's two arms.
## The adaptive shell: both branches run, nothing checks which one rendered `MainActivity.kt:113-149` (`useRail`, the `NavigationRail`-in-a-`Row` vs `Scaffold(bottomBar = { NavigationBar { … } })`) and `:154-159` (`Content`). This is an **assertion** gap, not a coverage gap, and that is the point. JaCoCo is green on the layout branches — `AppRootRestorationTest` drives `Compact` and `Expanded` — but `grep -rn 'NavigationRail\|NavigationBar\|useRail' app/src/test app/src/androidTest` returns nothing. **Swapping the two bodies passes the entire suite.** This is the shape `CLAUDE.md` records from the mutation review: green is not evidence. Two more facts in the same place: - **`WindowWidthSizeClass.Medium` appears in no test at all.** The code folds it into the rail branch via `!= Compact`; changing that to `== Expanded` would silently break tablet and foldable layouts with nothing failing. - **`Content` is 0%** (`MainActivityKt.Content`, 6 lines, 3 of 3 branches). Every existing test passes a stub `content` lambda, so the CONVERT→`ConverterScreen` / JOIN→`JoinScreen` mapping is never rendered by anything. This is what `AppRoot`'s own KDoc (`:85-96`) says the shell exists for: *"it has to lay out properly at every width"*, citing targetSdk 37's forced resizing. ## Feasibility: checked, and it works Rendering `AppRoot` with its **default** content reaches `ConverterScreen`'s `viewModel: ConversionViewModel = viewModel()`, which needs a `ViewModelStoreOwner` — and every existing test uses `createComposeRule`, which supplies none. Measured on `main` before filing: `createAndroidComposeRule<ComponentActivity>()` works under Robolectric here. A spike rendering `AppRoot(WindowWidthSizeClass.Compact)` with default content found `converter.chooseFile`, clicked the Join tab, found `join.chooseFiles`, and passed in 10.4s — then went red when `Content`'s two arms were transposed. So `Content` is **in scope**; no seam is needed. Two things make it work, both already true: both ViewModels are `@JvmOverloads constructor(app: Application, …)` with defaults, so `AndroidViewModelFactory` builds them; and `app/build.gradle.kts` states that `ui-test-manifest`'s `debugImplementation` entry already supplies the `ComponentActivity` to the merged manifest the unit tests build against. Use the **v2** rule (`androidx.compose.ui.test.junit4.v2.createAndroidComposeRule`) to match the repo's existing v2 `createComposeRule`; the non-v2 one compiles with a deprecation warning. The test needs `installTestWorkManager` and the `ConversionDependencies` fakes in `@Before`, as `ScreenWiringTest` does. ## Acceptance: three mutations, all must go red 1. Swap the `NavigationRail` and `NavigationBar` bodies. 2. Change `widthSizeClass != WindowWidthSizeClass.Compact` to `== WindowWidthSizeClass.Expanded` (this is what the `Medium` case is for). 3. Transpose `Content`'s two arms.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: JMR-dev/LibreMediaConverter#173