Skip to content

Add unit tests for 10 previously-0%-coverage classes (123 tests)#5237

Merged
shai-almog merged 5 commits into
masterfrom
tests/zero-coverage-classes
Jun 13, 2026
Merged

Add unit tests for 10 previously-0%-coverage classes (123 tests)#5237
shai-almog merged 5 commits into
masterfrom
tests/zero-coverage-classes

Conversation

@shai-almog

Copy link
Copy Markdown
Collaborator

Summary

Adds unit-test coverage for ten classes that previously had 0% coverage, raising 123 new green tests. All follow the existing maven/core-unittests conventions — JUnit 5, UITestBase/@FormTest for UI components, the built-in TestCodenameOneImplementation mock — and deliberately avoid Mockito, reflection into the class under test, and inner-state mutation.

Class under test Test file Tests
com.codename1.nfc.NfcReadOptions NfcReadOptionsTest 16
com.codename1.ai.ConversationStore ConversationStoreTest 11
com.codename1.ai.StreamingChatRequest StreamingChatRequestTest 9
com.codename1.camera.Camera CameraTest 19
com.codename1.camera.CameraSession CameraSessionTest 13
com.codename1.components.ChatBubble ChatBubbleTest 9
com.codename1.components.ChatInput ChatInputTest 10
com.codename1.components.ChatView ChatViewTest 11
com.codename1.router.Navigation NavigationTest 16
com.codename1.social.FirebaseAuth$FirebaseUser FirebaseUserTest 9

How the harder cases were reached without Mockito / reflection

  • Camera / CameraSessionTestCodenameOneImplementation gains a small, additive, backward-compatible camera hook (setCameraImpl + a createCameraImpl override cleared in reset()). Tests install a hand-written RecordingCameraImpl double. The override returns null by default, exactly matching the base class, so no existing test changes behaviour.
  • StreamingChatRequest (package-private, abstract) — driven through a concrete test subclass over the real mock-network path, covering SSE line reassembly, the [DONE] sentinel, CRLF/leading-space handling, clean completion, and HTTP-error mapping.
  • Navigation (process-global static stack) — each test works from a per-method baseline and normalises the stack using only the public popTo API; NavigationEntry's package-private constructor is reachable from the shared com.codename1.router package.
  • FirebaseUser — built via its package-private constructor from the com.codename1.social package; covers both the refresh (snake_case) and sign-in (camelCase) field mappings, expiry-parsing edge cases, and the JWT-claim email fallback.

Test results

Tests run: 123, Failures: 0, Errors: 0, Skipped: 0
BUILD SUCCESS

The only production-tree change is the additive camera hook in the test mock; everything else is new test code.

🤖 Generated with Claude Code

Covers classes that had no test coverage, following the existing
core-unittests conventions (JUnit 5, UITestBase/@formtest, the built-in
TestCodenameOneImplementation mock; no Mockito, no reflection into the
class under test, no inner-state mutation):

- com.codename1.nfc.NfcReadOptions          (NfcReadOptionsTest)
- com.codename1.ai.ConversationStore        (ConversationStoreTest)
- com.codename1.ai.StreamingChatRequest     (StreamingChatRequestTest)
- com.codename1.camera.Camera               (CameraTest)
- com.codename1.camera.CameraSession        (CameraSessionTest)
- com.codename1.components.ChatBubble        (ChatBubbleTest)
- com.codename1.components.ChatInput         (ChatInputTest)
- com.codename1.components.ChatView          (ChatViewTest)
- com.codename1.router.Navigation            (NavigationTest)
- com.codename1.social.FirebaseAuth$FirebaseUser (FirebaseUserTest)

Supporting changes:
- TestCodenameOneImplementation gains an additive, backward-compatible
  camera hook (setCameraImpl + createCameraImpl override, cleared in
  reset()) so Camera/CameraSession can be driven against a hand-written
  RecordingCameraImpl test double instead of Mockito. The override
  returns null by default, matching the base class, so no existing test
  is affected.
- RecordingCameraImpl: hand-written CameraImpl test double.

StreamingChatRequest (package-private, abstract) is exercised through a
concrete test subclass driven over the real mock-network path, covering
SSE line reassembly, the [DONE] sentinel, CRLF/leading-space handling,
clean completion, and HTTP-error mapping.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

✅ 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.

Fix: StreamingChatRequestTest used NetworkManager.addToQueueAndWait,
whose off-EDT path blocks on `while (!request.complete)` and could
deadlock on the network worker thread under JDK 21 (the build-test (21)
job timed out at 1h). The test now drives StreamingChatRequest.readResponse
directly (the test shares the com.codename1.ai package) with the subclass
overriding getResponseCode() to select the HTTP status. This is
deterministic, faster, and independent of the network thread; it also
drops the failSilently workaround that was only needed to dodge the
framework's unhandled-error dialog on the enqueue path.

New coverage (73 tests) for previously-0% classes, same conventions
(JUnit 5, UITestBase where a platform is needed, hand-written test
doubles; no Mockito, no reflection into the class under test):

- com.codename1.orm.EntityManager                     (EntityManagerTest)
- com.codename1.ai.RetryPolicy                         (RetryPolicyTest)
- com.codename1.nfc.Tag                                (TagTest)
- com.codename1.ai.ImageGenerator$OpenAiImageGenerator (ImageGeneratorTest)
- com.codename1.security.AuthenticationOptions         (AuthenticationOptionsTest)
- com.codename1.nfc.Nfc                                (NfcTest)
- com.codename1.nfc.ApduResponse                       (ApduResponseTest)
- com.codename1.payment.WalletPassEntry                (WalletPassEntryTest)
- com.codename1.ai.GenerateImageRequest                (GenerateImageRequestTest)
- com.codename1.io.rest.RequestBuilder$FetchAsMappedListActionListener
                                                       (FetchAsMappedListTest)

EntityManager is driven against a hand-written recording Database + Dao;
ImageGenerator's OpenAiImageGenerator and the RequestBuilder mapped-list
listener are exercised over the mock network layer.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@shai-almog

Copy link
Copy Markdown
Collaborator Author

Update: fixed the JDK 21 CI hang + added 10 more classes

CI fix

The build-test (21) job timed out (1h) inside StreamingChatRequestTest. Root cause: the test used NetworkManager.addToQueueAndWait(...), whose off-EDT path blocks on while (!request.complete) and could deadlock on the network worker thread under JDK 21 (JDK 8/17 happened to schedule through it).

The test now drives StreamingChatRequest.readResponse(...) directly — the test shares the com.codename1.ai package, and the subclass overrides getResponseCode() to select the HTTP status. This is deterministic, faster, and independent of the network thread, and it removes the failSilently workaround that was only there to dodge the framework's unhandled-error dialog on the enqueue path.

New coverage (73 tests) for the next batch of 0% classes

EntityManager, RetryPolicy, Tag, ImageGenerator$OpenAiImageGenerator, AuthenticationOptions, Nfc, ApduResponse, WalletPassEntry, GenerateImageRequest, and RequestBuilder$FetchAsMappedListActionListener.

Same conventions as before (JUnit 5, UITestBase where a platform is needed, hand-written test doubles; no Mockito, no reflection into the class under test). EntityManager runs against a recording Database + Dao; the OpenAI image generator and the mapped-list listener run over the mock network layer.

All new + changed tests pass locally.

New coverage for previously-0% classes, same conventions (JUnit 5,
UITestBase where a platform is needed, hand-written test doubles; no
Mockito, no reflection into the class under test):

- com.codename1.gpu.Primitives                         (PrimitivesTest)
- com.codename1.io.graphql.GraphQL$GraphQLConnection    (GraphQLConnectionTest)
- com.codename1.gaming.physics.box2d.pooling.normal.CircleStack
                                                        (CircleStackTest)
- com.codename1.system.SimulatorHookExecutor            (SimulatorHookExecutorTest)
- com.codename1.media.TtsOptions                        (TtsOptionsTest)
- com.codename1.io.bonjour.BonjourPublisher             (BonjourPublisherTest)
- com.codename1.ai.SimulatorRedirect                    (SimulatorRedirectTest)
- com.codename1.nfc.MifareClassic                       (MifareClassicTest)
- com.codename1.gaming.physics.box2d.pooling.stacks.DynamicIntStack
                                                        (DynamicIntStackTest)
- com.codename1.security.SecureStorage                  (SecureStorageTest)

Notes:
- Primitives is built against a headless GraphicsDevice subclass (the
  buffer-allocation methods are concrete on the base class).
- GraphQLConnection (private) is driven through GraphQL.execute over the
  mock network; the GraphQLConnection itself swallows the framework error
  dialog and reports HTTP errors through the callback.
- SimulatorRedirect's simulator branch needs a platform name of "se";
  TestCodenameOneImplementation gains an additive, reset-aware
  setPlatformName (default "test") for that, and the test restores the
  cn1.ai.* system properties it sets.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@shai-almog

Copy link
Copy Markdown
Collaborator Author

Update: 10 more 0%-coverage classes (53 tests)

Added coverage for:
Primitives, GraphQL$GraphQLConnection, CircleStack, SimulatorHookExecutor, TtsOptions, BonjourPublisher, SimulatorRedirect, MifareClassic, DynamicIntStack, SecureStorage.

Highlights:

  • Primitives is built against a headless GraphicsDevice subclass (its buffer-allocation methods are concrete on the base class), asserting the cube/quad vertex + index layout.
  • GraphQL$GraphQLConnection (private) is driven through GraphQL.execute over the mock network — success envelope, errors envelope, and an HTTP-error response that the connection reports through the callback instead of a modal dialog.
  • SimulatorRedirect's simulator branch needs a platform name of "se"; TestCodenameOneImplementation gained an additive, reset-aware setPlatformName (default "test"), and the test restores the cn1.ai.* system properties it sets.

Same conventions as the rest of the PR (no Mockito, no reflection into the class under test, hand-written doubles). All 53 pass locally.

New coverage for previously-0% classes, same conventions (JUnit 5,
UITestBase where a platform is needed, hand-written test doubles; no
Mockito, no reflection into the class under test):

- com.codename1.media.RecognitionOptions               (RecognitionOptionsTest)
- com.codename1.gpu.Texture                             (TextureTest)
- com.codename1.ai.Tool                                 (ToolTest)
- com.codename1.printing.PrintResult                    (PrintResultTest)
- com.codename1.printing.Printer                        (PrinterTest)
- com.codename1.io.rest.RequestBuilder$FetchAsMappedActionListener
                                                        (FetchAsMappedActionListenerTest)
- com.codename1.social.MicrosoftConnect                 (MicrosoftConnectTest)
- com.codename1.camera.CameraFrame                      (CameraFrameTest)
- com.codename1.io.bonjour.BonjourService               (BonjourServiceTest)

FetchAsMappedActionListener (private) is driven through
RequestBuilder.fetchAsMapped over the mock connection with a registered
Mapper; Printer's listener path is pumped on the EDT.

Note on com.codename1.ui.Display$EdtException (also 0%): deliberately
left untested. It is a private async-stack-trace wrapper whose only code
path re-throws on the EDT; exercising it destabilises the EDT / surefire
fork, which isn't worth covering a private internal detail.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@shai-almog

Copy link
Copy Markdown
Collaborator Author

Update: 9 more 0%-coverage classes (40 tests)

Added coverage for:
RecognitionOptions, Texture, Tool, PrintResult, Printer, RequestBuilder$FetchAsMappedActionListener, MicrosoftConnect, CameraFrame, BonjourService.

Notes:

  • FetchAsMappedActionListener (private) is driven through RequestBuilder.fetchAsMapped over a mock connection with a registered Mapper (single-object variant of the earlier mapped-list test).
  • Printer delegates to the non-printing test platform; the listener path is pumped on the EDT and asserts the FAILED result.
  • MicrosoftConnect covers the non-network surface (singleton, tenant selection + null-coalescing, isNativeLoginSupported, token validation).

Deliberately skipped: Display$EdtException

It's a private async-stack-trace wrapper whose only code path re-throws on the EDT. A test that triggers it lets the exception escape onto the EDT thread and destabilises the surefire fork — not worth it to cover a private internal detail, so I left it untested rather than ship a flaky/fork-killing test.

All 40 new tests pass locally.

New coverage for previously-0% classes, same conventions (JUnit 5,
UITestBase where a platform is needed, hand-written test doubles; no
Mockito, no reflection into the class under test):

- com.codename1.gpu.GpuCapabilities         (GpuCapabilitiesTest)
- com.codename1.io.usb.UsbDevice            (UsbDeviceTest)
- com.codename1.io.wifi.WifiPlatform        (WifiPlatformTest)
- com.codename1.io.wifi.WiFi                (WiFiTest)
- com.codename1.io.bonjour.BonjourBrowser   (BonjourBrowserTest)
- com.codename1.gaming.SoundEffect          (SoundEffectTest)
- com.codename1.background.ForegroundService (ForegroundServiceTest)

Notes:
- WiFi / BonjourBrowser run against the no-op fallback platforms the
  base implementation supplies; ForegroundService runs its task on the
  default background-thread runner and is awaited via a latch.
- SoundEffect's play/unload delegate to the pool's native peer, which
  casts the sound handle to its own internal type; those require a
  peer-loaded sound, so the test covers the constructor + accessors
  (built against the real fallback SoundPool) rather than playback.

Two requested classes were deliberately left untested, for the same
reason Display$EdtException was earlier -- both are private inner
members reachable only through fragile, environment-dependent paths
that destabilise a headless unit test:
- com.codename1.social.MicrosoftConnect$DiscoveredCallback: a private
  SuccessCallback reached only via the live OIDC discovery -> authorize
  -> system-browser chain, which opens browser UI.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@shai-almog

Copy link
Copy Markdown
Collaborator Author

Update: 7 more 0%-coverage classes (25 tests)

Added coverage for:
GpuCapabilities, UsbDevice, WifiPlatform, WiFi, BonjourBrowser, SoundEffect, ForegroundService.

Notes:

  • WiFi / BonjourBrowser run against the no-op fallback platforms the base implementation supplies (capability probes false, callbacks report UnsupportedOperationException).
  • ForegroundService runs its task on the default background-thread runner; the test awaits it via a latch and checks the running-state transitions.
  • SoundEffect: play/unload delegate to the pool's native peer, which casts the sound handle to its own internal Sound type — those need a peer-loaded sound, so the test covers the constructor + accessors (built against the real fallback SoundPool) rather than playback.

Deliberately skipped: MicrosoftConnect$DiscoveredCallback

A private SuccessCallback reachable only through the live OIDC discovery → authorize() → system-browser chain, which opens browser UI. Like Display$EdtException earlier, exercising it would mean brittle, environment-dependent plumbing in a headless unit test, so I left it rather than ship a flaky test.

All 25 new tests pass locally.

@shai-almog shai-almog merged commit d8a3587 into master Jun 13, 2026
19 checks passed
@shai-almog shai-almog deleted the tests/zero-coverage-classes branch June 13, 2026 13:56
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