R38.3 — The three simple pickers: selection in, the right enum out #59

Closed
opened 2026-08-23 23:06:56 +00:00 by JMR-dev · 0 comments
JMR-dev commented 2026-08-23 23:06:56 +00:00 (Migrated from github.com)

Child 3 of 8 decomposing #52. Depends on R38.1. The smallest child — a good first one.

Scope

FormatPicker :238, QualityPicker :375, EnginePicker :391. All three are the same shape: chips
in, selection out, no state of their own.

For each:

  • the chip matching the selected parameter reports as selected, and the others do not
  • clicking a chip invokes the callback with the right enum constant

Reference the enums, never retyped literals

Chip text comes from OutputFormat.label, QualityTier.label and Container.label. Retyping those
strings into the test turns a rename into a red test for no reason.

EnginePreference is the exception — it has no label property. Its three display strings live
in ConverterScreen.kt:406-410 ("Automatic", "Prefer hardware", "Force software") as a when
inside the screen file. Locate those by tag, or assert against that helper directly now that R38.1
has made it internal.

QualityTier also carries a description rendered at :388 — "Hardware accelerated. Best for sharing and batches." / "Software encode with CRF. Slower, smaller files.".

Acceptance — the mutation

Make one chip's onClick a no-op -> red.

Second bite: invert the selected == comparison -> the selection test goes red.

Size

~110 lines, one file. Independent of R38.2 and R38.4.


Traps (shared across the R38 children)

  • The import pair is mixed: androidx.compose.ui.test.junit4.v2.createComposeRule (v2) but
    androidx.compose.ui.test.junit4.StateRestorationTester (non-v2). Every tutorial shows the
    non-v2 rule. Copy both lines from AppRootRestorationTest.
  • @UnstableApi propagates. Both screens carry it, so a test class touching them needs it or the
    build fails on UnsafeOptInUsageError.
  • @RunWith(RobolectricTestRunner::class) and nothing else. There is no @Config in this repo;
    sdk=36 is set once in app/src/test/resources/robolectric.properties because Robolectric 4.16.1
    has no android-all jar for API 37.
  • DetailRow renders "$label: $value" as one node (ConverterScreen.kt:486).
    onNodeWithText("Container") will not match — use the full string or substring = true.
  • Typographic characters retyped as ASCII fail silently: … U+2026, — U+2014, × U+00D7,
    · U+00B7. Copy them out of the source.
  • Assertions are org.junit.Assert.*, statically imported one per symbol. No kotlin.test, no
    Truth, no mockk — test doubles are hand-written subclasses.
  • Open the test class with a KDoc naming the defect it bites on. House style, and it is what makes
    the mutation check reviewable by someone else.

Done means

./gradlew :app:assembleDebug :app:testDebugUnitTest :app:compileDebugAndroidTestKotlin :app:ktlintCheck :app:detekt :app:lintDebug --continue

then the mutation above: revert the named line, watch the named test go red, restore, and quote what
the failure said. Per CLAUDE.md, own branch, own PR, never on main.

Parent: #52

_Child 3 of 8 decomposing #52. **Depends on R38.1.** The smallest child — a good first one._ ### Scope `FormatPicker` :238, `QualityPicker` :375, `EnginePicker` :391. All three are the same shape: chips in, selection out, no state of their own. For each: - the chip matching the `selected` parameter reports as selected, and the others do not - clicking a chip invokes the callback **with the right enum constant** ### Reference the enums, never retyped literals Chip text comes from `OutputFormat.label`, `QualityTier.label` and `Container.label`. Retyping those strings into the test turns a rename into a red test for no reason. **`EnginePreference` is the exception — it has no `label` property.** Its three display strings live in `ConverterScreen.kt:406-410` (`"Automatic"`, `"Prefer hardware"`, `"Force software"`) as a `when` inside the screen file. Locate those by tag, or assert against that helper directly now that R38.1 has made it `internal`. `QualityTier` also carries a `description` rendered at `:388` — `"Hardware accelerated. Best for sharing and batches."` / `"Software encode with CRF. Slower, smaller files."`. ### Acceptance — the mutation Make one chip's `onClick` a no-op -> red. Second bite: invert the `selected ==` comparison -> the selection test goes red. ### Size ~110 lines, one file. Independent of R38.2 and R38.4. --- ### Traps (shared across the R38 children) - **The import pair is mixed**: `androidx.compose.ui.test.junit4.v2.createComposeRule` (**v2**) but `androidx.compose.ui.test.junit4.StateRestorationTester` (**non-v2**). Every tutorial shows the non-v2 rule. Copy both lines from `AppRootRestorationTest`. - **`@UnstableApi` propagates.** Both screens carry it, so a test class touching them needs it or the build fails on `UnsafeOptInUsageError`. - **`@RunWith(RobolectricTestRunner::class)` and nothing else.** There is no `@Config` in this repo; `sdk=36` is set once in `app/src/test/resources/robolectric.properties` because Robolectric 4.16.1 has no `android-all` jar for API 37. - **`DetailRow` renders `"$label: $value"` as one node** (`ConverterScreen.kt:486`). `onNodeWithText("Container")` will not match — use the full string or `substring = true`. - **Typographic characters retyped as ASCII fail silently**: `…` U+2026, `—` U+2014, `×` U+00D7, `·` U+00B7. Copy them out of the source. - **Assertions are `org.junit.Assert.*`, statically imported one per symbol.** No `kotlin.test`, no Truth, no mockk — test doubles are hand-written subclasses. - **Open the test class with a KDoc naming the defect it bites on.** House style, and it is what makes the mutation check reviewable by someone else. ### Done means `./gradlew :app:assembleDebug :app:testDebugUnitTest :app:compileDebugAndroidTestKotlin :app:ktlintCheck :app:detekt :app:lintDebug --continue` then the mutation above: revert the named line, watch the named test go red, restore, and quote what the failure said. Per `CLAUDE.md`, own branch, own PR, never on `main`. Parent: #52
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: JMR-dev/LibreMediaConverter#59