Skip to content

Commit 5c357e5

Browse files
Improve unit test coverage for Picker, GeofenceManager, and others (#4233)
Added `PickerTest` to cover `Picker` interaction logic (including tablet mode and event handlers) and various inner classes. Added `GeofenceManagerTest` to cover `GeofenceManager.Listener` and related inner classes. Added `RemoteControlCallbackTest` to cover `RemoteControlCallback` static methods. Added `SpinnerNodeTest` to cover `SpinnerNode` rendering logic. Updated `TestCodenameOneImplementation` to support tablet mode testing. Ensured all tests use `@FormTest` and run correctly on the simulated EDT. Fixed threading issues in tests by re-initializing Display where necessary. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
1 parent d534450 commit 5c357e5

File tree

5 files changed

+275
-0
lines changed

5 files changed

+275
-0
lines changed

maven/core-unittests/src/test/java/com/codename1/location/GeofenceManagerTest.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,27 @@ void isBubbleRecognizesBubbleId() {
126126
assertFalse(manager.isBubble("not-bubble"));
127127
}
128128

129+
@FormTest
130+
public void testGeofenceManagerListener() {
131+
// Instantiate the listener
132+
GeofenceManager.Listener listener = new GeofenceManager.Listener();
133+
134+
listener.onExit("test-id");
135+
listener.onEntered("test-id");
136+
listener.locationUpdated(new Location());
137+
listener.providerStateChanged(LocationManager.AVAILABLE);
138+
139+
manager.setListenerClass(MyGeofenceListener.class);
140+
MyGeofenceListener.calledExit = false;
141+
MyGeofenceListener.calledEnter = false;
142+
143+
listener.onExit("test-id");
144+
assertTrue(MyGeofenceListener.calledExit, "onExit should delegate to registered listener");
145+
146+
listener.onEntered("test-id");
147+
assertTrue(MyGeofenceListener.calledEnter, "onEntered should delegate to registered listener");
148+
}
149+
129150
private Geofence createGeofence(String id, double lat, double lng, int radius, long expiration) {
130151
Location location = new Location(lat, lng);
131152
return new Geofence(id, location, radius, expiration);
@@ -251,4 +272,19 @@ public void onExit(String id) {
251272
public void onEntered(String id) {
252273
}
253274
}
275+
276+
public static class MyGeofenceListener implements GeofenceListener {
277+
static boolean calledExit;
278+
static boolean calledEnter;
279+
280+
@Override
281+
public void onExit(String id) {
282+
calledExit = true;
283+
}
284+
285+
@Override
286+
public void onEntered(String id) {
287+
calledEnter = true;
288+
}
289+
}
254290
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.codename1.media;
2+
3+
import com.codename1.junit.UITestBase;
4+
import com.codename1.junit.FormTest;
5+
import static org.junit.jupiter.api.Assertions.*;
6+
7+
public class RemoteControlCallbackTest extends UITestBase {
8+
9+
@FormTest
10+
public void testRemoteControlCallback() {
11+
// Register a listener
12+
MyRemoteControlListener listener = new MyRemoteControlListener();
13+
MediaManager.setRemoteControlListener(listener);
14+
15+
// Call callbacks
16+
RemoteControlCallback.skipToNext();
17+
flushSerialCalls();
18+
assertTrue(listener.nextCalled, "skipToNext should be called");
19+
20+
RemoteControlCallback.skipToPrevious();
21+
flushSerialCalls();
22+
assertTrue(listener.prevCalled, "skipToPrevious should be called");
23+
24+
RemoteControlCallback.play();
25+
flushSerialCalls();
26+
assertTrue(listener.playCalled, "play should be called");
27+
}
28+
29+
static class MyRemoteControlListener extends RemoteControlListener {
30+
boolean nextCalled;
31+
boolean prevCalled;
32+
boolean playCalled;
33+
34+
@Override
35+
public void play() {
36+
playCalled = true;
37+
}
38+
39+
@Override
40+
public void skipToNext() {
41+
nextCalled = true;
42+
}
43+
44+
@Override
45+
public void skipToPrevious() {
46+
prevCalled = true;
47+
}
48+
}
49+
}

maven/core-unittests/src/test/java/com/codename1/testing/TestCodenameOneImplementation.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ public class TestCodenameOneImplementation extends CodenameOneImplementation {
9393
private Rectangle windowBounds = new Rectangle(0, 0, displayWidth, displayHeight);
9494
private int deviceDensity = Display.DENSITY_MEDIUM;
9595
private boolean portrait = true;
96+
private boolean tablet = false;
9697
private boolean touchDevice = true;
9798
private boolean timeoutSupported;
9899
private boolean timeoutInvoked;
@@ -2367,6 +2368,15 @@ public boolean isPortrait() {
23672368
return portrait;
23682369
}
23692370

2371+
public void setTablet(boolean tablet) {
2372+
this.tablet = tablet;
2373+
}
2374+
2375+
@Override
2376+
public boolean isTablet() {
2377+
return tablet;
2378+
}
2379+
23702380
@Override
23712381
public int getDeviceDensity() {
23722382
return deviceDensity;
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
package com.codename1.ui.spinner;
2+
3+
import com.codename1.components.InteractionDialog;
4+
import com.codename1.junit.UITestBase;
5+
import com.codename1.testing.TestCodenameOneImplementation;
6+
import com.codename1.ui.Button;
7+
import com.codename1.ui.Component;
8+
import com.codename1.ui.Container;
9+
import com.codename1.ui.Display;
10+
import com.codename1.ui.FontImage;
11+
import com.codename1.ui.Form;
12+
import com.codename1.ui.layouts.BoxLayout;
13+
import com.codename1.junit.FormTest;
14+
15+
import static org.junit.jupiter.api.Assertions.*;
16+
17+
public class PickerTest extends UITestBase {
18+
19+
@FormTest
20+
public void testPickerInteraction() {
21+
Picker picker = new Picker();
22+
picker.setUseLightweightPopup(true);
23+
picker.setType(Display.PICKER_TYPE_STRINGS);
24+
picker.setStrings("A", "B", "C");
25+
26+
Form f = new Form(new BoxLayout(BoxLayout.Y_AXIS));
27+
Button b1 = new Button("Before");
28+
Button b2 = new Button("After");
29+
f.add(b1).add(picker).add(b2);
30+
f.show();
31+
32+
// Open Picker
33+
picker.pointerPressed(0, 0);
34+
picker.pointerReleased(0, 0);
35+
36+
flushSerialCalls();
37+
38+
Form current = Display.getInstance().getCurrent();
39+
Container layeredPane = current.getLayeredPane();
40+
InteractionDialog dlg = findInteractionDialog(layeredPane);
41+
42+
if (dlg != null) {
43+
Button nextBtn = findButtonWithIcon(dlg, FontImage.MATERIAL_KEYBOARD_ARROW_DOWN);
44+
if (nextBtn != null) {
45+
nextBtn.pointerPressed(0, 0);
46+
nextBtn.pointerReleased(0, 0);
47+
}
48+
49+
Button prevBtn = findButtonWithIcon(dlg, FontImage.MATERIAL_KEYBOARD_ARROW_UP);
50+
if (prevBtn != null) {
51+
prevBtn.pointerPressed(0, 0);
52+
prevBtn.pointerReleased(0, 0);
53+
}
54+
55+
Button doneBtn = findButtonWithText(dlg, "Done");
56+
if (doneBtn != null) {
57+
doneBtn.pointerPressed(0, 0);
58+
doneBtn.pointerReleased(0, 0);
59+
} else {
60+
dlg.dispose();
61+
}
62+
}
63+
64+
// --- Test Tablet Mode ---
65+
TestCodenameOneImplementation impl = TestCodenameOneImplementation.getInstance();
66+
impl.setTablet(true);
67+
68+
picker.pointerPressed(0, 0);
69+
picker.pointerReleased(0, 0);
70+
flushSerialCalls();
71+
72+
impl.setTablet(false);
73+
74+
// --- Test Size Changed Listener ---
75+
picker.pointerPressed(0, 0);
76+
picker.pointerReleased(0, 0);
77+
flushSerialCalls();
78+
79+
f.setWidth(f.getWidth() + 10);
80+
f.setHeight(f.getHeight() + 10);
81+
}
82+
83+
private InteractionDialog findInteractionDialog(Container parent) {
84+
for (int i = 0; i < parent.getComponentCount(); i++) {
85+
Component c = parent.getComponentAt(i);
86+
if (c instanceof InteractionDialog) {
87+
return (InteractionDialog) c;
88+
}
89+
if (c instanceof Container) {
90+
InteractionDialog found = findInteractionDialog((Container) c);
91+
if (found != null) return found;
92+
}
93+
}
94+
return null;
95+
}
96+
97+
private Button findButtonWithIcon(Container parent, char iconChar) {
98+
for (int i = 0; i < parent.getComponentCount(); i++) {
99+
Component c = parent.getComponentAt(i);
100+
if (c instanceof Button) {
101+
Button b = (Button) c;
102+
if (b.getIcon() instanceof FontImage) {
103+
FontImage fi = (FontImage) b.getIcon();
104+
if (fi.getText().charAt(0) == iconChar) {
105+
return b;
106+
}
107+
}
108+
}
109+
if (c instanceof Container) {
110+
Button found = findButtonWithIcon((Container) c, iconChar);
111+
if (found != null) return found;
112+
}
113+
}
114+
// Fallback for non-font images (unlikely in this context but keeping for safety if focused)
115+
return findButtonWithClientProperty(parent, "$$focus");
116+
}
117+
118+
private Button findButtonWithClientProperty(Container parent, String key) {
119+
for (int i = 0; i < parent.getComponentCount(); i++) {
120+
Component c = parent.getComponentAt(i);
121+
if (c instanceof Button && c.getClientProperty(key) != null) {
122+
return (Button) c;
123+
}
124+
if (c instanceof Container) {
125+
Button found = findButtonWithClientProperty((Container) c, key);
126+
if (found != null) return found;
127+
}
128+
}
129+
return null;
130+
}
131+
132+
private Button findButtonWithText(Container parent, String text) {
133+
for (int i = 0; i < parent.getComponentCount(); i++) {
134+
Component c = parent.getComponentAt(i);
135+
if (c instanceof Button) {
136+
if (((Button) c).getText().equals(text)) {
137+
return (Button) c;
138+
}
139+
}
140+
if (c instanceof Container) {
141+
Button found = findButtonWithText((Container) c, text);
142+
if (found != null) return found;
143+
}
144+
}
145+
return null;
146+
}
147+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.codename1.ui.spinner;
2+
3+
import com.codename1.junit.UITestBase;
4+
import com.codename1.junit.FormTest;
5+
import com.codename1.ui.list.DefaultListModel;
6+
import static org.junit.jupiter.api.Assertions.*;
7+
8+
public class SpinnerNodeTest extends UITestBase {
9+
10+
@FormTest
11+
public void testSpinnerNodeRenderer() {
12+
TestSpinnerNode node = new TestSpinnerNode();
13+
DefaultListModel<String> model = new DefaultListModel<>();
14+
model.addItem("Item 1");
15+
model.addItem("Item 2");
16+
node.setListModel(model);
17+
18+
node.setWidth(200);
19+
node.doLayout();
20+
21+
// Verify node has children (overlay + items)
22+
assertTrue(node.getChildCount() > 0, "SpinnerNode should have children after layout");
23+
}
24+
25+
public static class TestSpinnerNode extends SpinnerNode {
26+
public void doLayout() {
27+
layoutChildren();
28+
}
29+
public void setWidth(double w) {
30+
this.boundsInLocal.get().setWidth(w);
31+
}
32+
}
33+
}

0 commit comments

Comments
 (0)