Skip to content

ci: add simulator-init regression coverage for #4850#4861

Open
shai-almog wants to merge 2 commits intomasterfrom
ci/issue-4850-simulator-coverage
Open

ci: add simulator-init regression coverage for #4850#4861
shai-almog wants to merge 2 commits intomasterfrom
ci/issue-4850-simulator-coverage

Conversation

@shai-almog
Copy link
Copy Markdown
Collaborator

Summary

  • Adds three layers of coverage for the class of bug behind issue Unable to launch simulator because of Java.lang.StringIndexOutOfBoundsException in latest as of reporting (7.0.236) #4850 (StringIndexOutOfBoundsException at parseTextFieldInputMode during the forked cn1:css subprocess on every initializr/archetype project for users with the auto-update bundle pref toggled on).
  • Why it shipped: the existing cn1app-archetype-test.sh and tests/core.sh both invoke cn1:css, but JavaSEPort.enableAutoLocalizationBundle is gated on the per-user preference cn1.autoDefaultResourceBundle (default false). CI runners don't have the pref set; users with the simulator menu toggled at any point in CN1 history do. The bug was deterministic on user machines and silently bypassed in CI for ~6 months.
  • No production-code changes — coverage additions only. The actual fix is in master via ba8044ef0 / 2d1e1f83c.

What's in this PR

  1. tests/core/test/com/codename1/impl/javase/AutoLocalizationBundleTest.java — extended with verifySetBundleSmokeOnFreshProject, which constructs an AutoLocalizationBundle against an empty src/main/l10n (matching enableAutoLocalizationBundle) and hands it to UIManager.setBundle. Pre-fix this throws inside parseTextFieldInputMode; post-fix it installs cleanly. Catches both the @-key fabrication regression and any future setBundle break, independent of preference state.
  2. maven/integration-tests/inc/auto-bundle-pref.sh — helper that flips the Preferences.userRoot() node cn1:css's forked JVM reads. Used by cn1app-archetype-test.sh to force-on the gated branch for the duration of the build. The pref persists via ~/.java/.userPrefs, so the parent-process flush is visible to forked Maven plugin subprocesses.
  3. .github/workflows/archetype-smoke.yml — new path-gated PR job that generates an archetype project, installs xvfb, and runs the smoke. Previously the only end-to-end archetype build was ant.yml's bash all.sh, which runs only on push/PR to master and was the workflow that missed this regression.

Drive-by

maven/integration-tests/android-native-interface-test.sh started with bare exit 0 ("Failing for some reason... need to investigate, but will do it later"), so under all.sh's set -e it masqueraded as a green check. Added an explicit [SKIP] log line so the disablement shows up in suite output instead of pretending to pass.

Test plan

  • archetype-smoke.yml runs on this PR (path filter matches the modified files).
  • On archetype-smoke.yml, the Run archetype simulator smoke (auto-bundle pref forced on) step succeeds — meaning the forked CN1CSSCLI took the enableAutoLocalizationBundle branch and didn't crash.
  • ant.yml's bash tests/all.sh continues to pass with the extended AutoLocalizationBundleTest.
  • Manually verify on a clean Linux runner that set_auto_bundle_pref true sets the pref and a separate java invocation reads it back as true (validated locally; included for reviewer reference).

🤖 Generated with Claude Code

Issue #4850 (StringIndexOutOfBoundsException out of parseTextFieldInputMode)
shipped to end users despite cn1app-archetype-test.sh exercising cn1:css on
every PR-merge. Root cause of the coverage miss:
JavaSEPort.enableAutoLocalizationBundle is gated on the per-user preference
cn1.autoDefaultResourceBundle, which CI runners default to false but real
users have stuck to true via the simulator menu. The forked CN1CSSCLI took
the gated branch on user machines and not in CI for six months.

Three coverage additions, no production-code changes:

- tests/core/.../AutoLocalizationBundleTest.java: smoke-test the full
  simulator-init handoff (AutoLocalizationBundle for an empty l10n dir,
  installed via UIManager.setBundle) end-to-end. Catches the @-meta-key
  echo regression and any future setBundle/parseTextFieldInputMode break
  regardless of preference state.

- maven/integration-tests/inc/auto-bundle-pref.sh: helper that flips the
  Preferences.userRoot node Maven's forked CSS subprocess reads. Used by
  cn1app-archetype-test.sh to force the user-side branch on for the
  duration of the build, then unconditionally restore via trap.

- .github/workflows/archetype-smoke.yml: PR-time, path-gated job that
  generates an archetype project, installs xvfb, and runs the smoke test
  with the pref forced on. Previously this end-to-end exercise only ran
  on push/PR to master via ant.yml.

Also surfaces a pre-existing skip: android-native-interface-test.sh
started with bare `exit 0` ("Failing for some reason... need to investigate,
but will do it later"), masquerading as green in all.sh's set -e cascade.
Added an explicit [SKIP] log line so the disablement is visible in suite
output.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 4, 2026

✅ Continuous Quality Report

Test & Coverage

Static Analysis

  • SpotBugs [Report archive]
    • ByteCodeTranslator: 0 findings (no issues)
    • android: 0 findings (no issues)
    • codenameone-maven-plugin: 0 findings (no issues)
    • core-unittests: 0 findings (no issues)
    • ios: 0 findings (no issues)
  • PMD: 0 findings (no issues) [Report archive]
  • Checkstyle: 0 findings (no issues) [Report archive]

Generated automatically by the PR CI workflow.

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 4, 2026

Compared 86 screenshots: 86 matched.

Native Android coverage

  • 📊 Line coverage: 9.86% (5359/54372 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 7.75% (26311/339651), branch 3.58% (1166/32602), complexity 4.53% (1413/31210), method 7.95% (1158/14574), class 13.02% (254/1951)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

✅ Native Android screenshot tests passed.

Native Android coverage

  • 📊 Line coverage: 9.86% (5359/54372 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 7.75% (26311/339651), branch 3.58% (1166/32602), complexity 4.53% (1413/31210), method 7.95% (1158/14574), class 13.02% (254/1951)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

Benchmark Results

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 709.000 ms
Base64 CN1 encode 204.000 ms
Base64 encode ratio (CN1/native) 0.288x (71.2% faster)
Base64 native decode 558.000 ms
Base64 CN1 decode 137.000 ms
Base64 decode ratio (CN1/native) 0.246x (75.4% faster)
Image encode benchmark status skipped (SIMD unsupported)

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 4, 2026

Compared 82 screenshots: 82 matched.
✅ Native iOS screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 186 seconds

Build and Run Timing

Metric Duration
Simulator Boot 84000 ms
Simulator Boot (Run) 1000 ms
App Install 24000 ms
App Launch 7000 ms
Test Execution 287000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 1111.000 ms
Base64 CN1 encode 1440.000 ms
Base64 encode ratio (CN1/native) 1.296x (29.6% slower)
Base64 native decode 722.000 ms
Base64 CN1 decode 1049.000 ms
Base64 decode ratio (CN1/native) 1.453x (45.3% slower)
Base64 SIMD encode 510.000 ms
Base64 encode ratio (SIMD/native) 0.459x (54.1% faster)
Base64 encode ratio (SIMD/CN1) 0.354x (64.6% faster)
Base64 SIMD decode 416.000 ms
Base64 decode ratio (SIMD/native) 0.576x (42.4% faster)
Base64 decode ratio (SIMD/CN1) 0.397x (60.3% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 85.000 ms
Image createMask (SIMD on) 11.000 ms
Image createMask ratio (SIMD on/off) 0.129x (87.1% faster)
Image applyMask (SIMD off) 154.000 ms
Image applyMask (SIMD on) 54.000 ms
Image applyMask ratio (SIMD on/off) 0.351x (64.9% faster)
Image modifyAlpha (SIMD off) 132.000 ms
Image modifyAlpha (SIMD on) 64.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.485x (51.5% faster)
Image modifyAlpha removeColor (SIMD off) 175.000 ms
Image modifyAlpha removeColor (SIMD on) 63.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.360x (64.0% faster)
Image PNG encode (SIMD off) 1286.000 ms
Image PNG encode (SIMD on) 1327.000 ms
Image PNG encode ratio (SIMD on/off) 1.032x (3.2% slower)
Image JPEG encode 711.000 ms

ThomasH99 reports the same `parseTextFieldInputMode` crash on 7.0.237 even
with the @-key fabrication guard from `ba8044ef0` in place. Root cause: the
ba8044e fix only blocks NEW echoes for missing @-prefixed keys; it does
nothing for keys that older Codename One versions already echoed AND
persisted to disk. Existing user projects whose Bundle.properties contains
`@im=@im` and `@im-@im=@im-@im` from a prior simulator boot bypass the
@-prefix null-guard because `super.get` returns the persisted real value,
not null. setBundle then tokenizes "@im" -> ["@im"], looks up "@im-@im",
gets back the persisted "@im-@im", and crashes inside
`parseTextFieldInputMode("@im-@im")` on `substring(0, indexOf('='))` for a
token with no `=`.

Self-heal at load time:

- AutoLocalizationBundle.loadFromFile drops entries where the key starts
  with `@` and the value equals the key (the wormhole signature). The
  in-memory Hashtable never sees them, and the file is rewritten without
  them so the corruption clears permanently on the next boot.
- The check is intentionally narrow: only `@k=@k` self-references match.
  Legitimate meta-key data like `@rtl=true` or `@im=ABC|abc` flows through
  unchanged. Non-meta keys keep their normal "missing-translation echo"
  behavior because that's an intended developer aid.

Test:

- AutoLocalizationBundleTest.verifySetBundleHealsLegacyWormholeFile
  pre-populates a legacy Bundle.properties with `@im=@im`, `@im-@im=@im-@im`,
  `@rtl=@rtl`, plus a non-wormhole `hello=world`. After construction the
  Hashtable returns null for the three @-keys, the file no longer contains
  them, and the non-wormhole entry survives both in memory and on disk.
  UIManager.setBundle on the bundle no longer crashes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 4, 2026

Compared 7 screenshots: 7 matched.
✅ JavaSE simulator integration screenshots matched stored baselines.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant