mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-10 20:47:03 +01:00
Add docs/app-split-recipes.md; update the handoff to 78 left
Dart's library-scoped privates (use part/part of), Kotlin's lack of any equivalent (use an internal fixture object), and the TypeScript seams that compile clean and fail at runtime - three projects hit that last one. Also the per-project test baselines, including that gradle prints UP-TO-DATE rather than a count and needs JDK 21 pinned. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011w2Pj4Ek3ZNMQVYcFHgXDY
This commit is contained in:
parent
2ce86a5176
commit
34783a5022
78
docs/app-split-recipes.md
Normal file
78
docs/app-split-recipes.md
Normal file
@ -0,0 +1,78 @@
|
||||
# App split recipes (Dart, Kotlin, TypeScript)
|
||||
|
||||
Settled while clearing `focus_owner`, `kcd2_dice_solver` and
|
||||
`reverse_survivors`. Referenced from `refactor_claude_todo_resume.md`.
|
||||
|
||||
## Baselines — measure before editing, re-check after
|
||||
|
||||
| Project | Command | Expect |
|
||||
| ---------------------- | ------------------- | -------------- |
|
||||
| `focus_owner` (Dart) | `flutter test` | 94 |
|
||||
| `focus_owner` (Kotlin) | see below | 40, 0 failures |
|
||||
| `kcd2_dice_solver` | `npm test -- --run` | 288 |
|
||||
| `reverse_survivors` | `npm test -- --run` | 160 |
|
||||
|
||||
Gradle prints `UP-TO-DATE` rather than a count, so read the JUnit XML, and
|
||||
**pin the JDK** — the default JDK 26 breaks the AGP jlink transform:
|
||||
|
||||
```bash
|
||||
cd focus_owner/android
|
||||
JAVA_HOME=/usr/lib/jvm/java-21-openjdk ./gradlew testDebugUnitTest --offline
|
||||
grep -ho 'tests="[0-9]*"' ../build/app/test-results/testDebugUnitTest/*.xml \
|
||||
| grep -oP '\d+' | paste -sd+ | bc
|
||||
```
|
||||
|
||||
## Dart: privates are library-scoped, so use `part`
|
||||
|
||||
A separate file is a separate **library**, so `_Card` and friends are invisible
|
||||
to it. Splitting `main.dart` with `import` + `export` produced 30 errors of the
|
||||
form "The name `_Card` isn't a class". `part 'x.dart';` + `part of 'main.dart';`
|
||||
keeps both files in one library and the analyzer goes straight to zero issues.
|
||||
|
||||
The part file carries **no imports of its own** — it inherits the library's.
|
||||
|
||||
**A `part` cannot rescue a State class.** `status_page_state.dart` stayed over
|
||||
the cap: its methods call `setState` and read seven private fields, and a
|
||||
`mixin on State<...>` cannot see them without declaring the state twice.
|
||||
|
||||
**Splitting a widget test off its `testWidgets` group loses the binding.**
|
||||
Four tests failed with "Binding has not yet been initialized" because the
|
||||
group that had been initialising it implicitly moved away. Add
|
||||
`TestWidgetsFlutterBinding.ensureInitialized()` to **both** halves.
|
||||
|
||||
## Kotlin: no `part`, so use an internal fixture object
|
||||
|
||||
Shared `private val`/`private fun` test fixtures go into an
|
||||
`internal object XFixtures` in the same package, and each test class delegates
|
||||
to it. Two compile failures came from missing one (`installed`) — list every
|
||||
`private` member of the original class before cutting.
|
||||
|
||||
`EnforcementRunner.kt` is **not splittable** as it stands: its location block
|
||||
reads the private constructor property `context` and `prefs()` eleven times,
|
||||
which no extension function can reach.
|
||||
|
||||
## TypeScript: `tsc` does not tell you a split worked
|
||||
|
||||
Three separate projects had a seam that compiled clean and failed at runtime:
|
||||
|
||||
- an import cycle leaves a constant `undefined` at module-init
|
||||
(`HEADSTART_POINTS`, twice, in `kcd2`);
|
||||
- a moved function is simply not there (`survivorStep`, 63 failures);
|
||||
- a type name that collides with a DOM global resolves to the DOM one — the
|
||||
error talks about `anchorNode` rather than saying the name is missing.
|
||||
|
||||
**Always run the suite.** Prune the imports the split leaves behind by
|
||||
iterating on `tsc`'s own TS6133/TS6192/TS6196 output rather than guessing, but
|
||||
note it cannot see a helper another file still needs.
|
||||
|
||||
## Coverage: new files must land inside the include glob
|
||||
|
||||
`kcd2` and `reverse_survivors` both gate at 100%. New source modules are picked
|
||||
up automatically; **shared test fixtures must go in `src/test/`**, which the
|
||||
coverage `exclude` names by path. Beside the source they count as production
|
||||
code and break the gate — the same trap recorded for `poker-stakes`.
|
||||
|
||||
## A split that empties a file must delete it
|
||||
|
||||
`App.test.tsx` lost its last `describe` and vitest failed the whole run with
|
||||
"No test suite found in file". Remove the shell.
|
||||
@ -6,8 +6,9 @@
|
||||
|
||||
## Where things stand
|
||||
|
||||
**83 files** over 250 lines (was 183). Everything is committed and pushed to
|
||||
`main` at `093e2f6`; the tree is clean.
|
||||
**78 files** over 250 lines (was 183). Everything is committed and pushed to
|
||||
`main` at `2ce86a5`. `focus_owner/analysis_options.yaml` has an uncommitted
|
||||
change from an earlier session — **leave it unstaged**, it is not ours.
|
||||
|
||||
**`python_pkg/` is DONE — 50 violations → 0.** Do not reopen it. Cleared one
|
||||
package per tranche, pushing after each: `brother_printer` (15→0, suite pinned
|
||||
@ -62,8 +63,12 @@ Same in TypeScript: `kcd2`'s `search.ts` and `badgeValue.ts`, and
|
||||
caller's globals — stricter than `shellcheck -x` on the entry, and the check
|
||||
that decides whether a seam is real. Run it before believing a split.
|
||||
|
||||
Next: the remaining `main()`-shaped shell scripts, then `focus_owner` and
|
||||
`billsplit` (Kotlin+Dart, untouched so far — check for a test command first).
|
||||
Next: `billsplit` (Dart, untouched), then the remaining `main()`-shaped shell
|
||||
scripts. `focus_owner`'s six leftovers are four Kotlin sources that read a
|
||||
private `context`, one State class, and one test one line over.
|
||||
|
||||
Baselines and the per-language traps (Dart `part`, Kotlin fixture objects, the
|
||||
TS import cycle) are in `docs/app-split-recipes.md`.
|
||||
|
||||
## The live worklist
|
||||
|
||||
@ -136,10 +141,12 @@ Plus `.github/workflows/file-length.yml` modelled on
|
||||
|
||||
## Language recipes
|
||||
|
||||
- `docs/python-split-recipes.md` — the seam-selection rule, the `__all__`
|
||||
re-export form, the `TC001` trap, the mixin shape, and the coverage
|
||||
behaviour of new sibling modules. `python_pkg` is done; read it if a stray
|
||||
`.py` turns up, or for the seam rule, which generalises to any language.
|
||||
- `docs/python-split-recipes.md` — the seam-selection rule (generalises to
|
||||
every language), the `__all__` re-export form, the `TC001` trap and the
|
||||
mixin shape. `python_pkg` is done.
|
||||
- `docs/app-split-recipes.md` — Dart `part`, Kotlin fixture objects, the
|
||||
TypeScript import cycle that compiles clean, and the per-project test
|
||||
baselines. **Read before touching `billsplit` or `focus_owner`.**
|
||||
- `docs/shell-split-recipes.md` — **read this before the next
|
||||
`linux_configuration` split.** What replaces the pass count when there is no
|
||||
test suite, which scripts escape the repo, the lib shape that satisfies both
|
||||
@ -154,23 +161,10 @@ Each rule in both cost a failed gate run or a revert to establish.
|
||||
- **Shell** — extract into `lib/*.sh` sourced by a thin entry script. See
|
||||
`docs/shell-split-recipes.md` for the lib shape; note it corrects the old
|
||||
advice to repeat `set -euo pipefail` in every lib.
|
||||
- **Python** — extract cohesive helpers into sibling modules; keep the public
|
||||
API stable by re-exporting.
|
||||
- **TS/Dart** — extract components; re-export from the original path so no
|
||||
importer changes.
|
||||
- **Tests** — split by describe/test-group. Coverage must not drop, and
|
||||
**verify by the pass _count_, not a green run**: a split that loses a whole
|
||||
module still reports "passed".
|
||||
In `python_pkg`, shared fixture builders go in the package's
|
||||
**`tests/conftest.py`** — the `name-tests-test` hook rejects any other
|
||||
non-`test_*.py` file under `tests/`, so a `_helpers.py` will fail the gate.
|
||||
`python_pkg/syncyomi_guard/tests/conftest.py` is the precedent, and
|
||||
`meta/pyproject.toml` omits `*/tests/*` from coverage by path so nothing
|
||||
there is counted as production code (the opposite of the `poker-stakes`
|
||||
trap below). Prefer one shared conftest over another `partN` file: the repo
|
||||
already carries four, and each new one that redeclares the same fixture
|
||||
scaffolding pushes jscpd toward its 2% duplication threshold — which only
|
||||
fires on the real `git commit`.
|
||||
- **Python / TS / Dart / Kotlin** — see the two recipe docs above.
|
||||
- **Tests** — split by describe/test-group and **verify by the pass _count_,
|
||||
not a green run**: a split that loses a whole module still reports "passed".
|
||||
Shared fixtures go where the coverage config already excludes them.
|
||||
|
||||
Never game the cap: no one-lining, no deleting tests, no moving code into an
|
||||
exempt extension, no suppressions.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user