Skip to content

Commit 47558a4

Browse files
authored
Expand UI coverage for CN, ComponentSelector, Toolbar, and Dialog (#4148)
* Expand UI coverage for CN proxies and dialogs * Fix CN and ComponentSelector test coverage * Handle callSeriallyAndWait on EDT in CNTest * Replace assertThrows usage in CNTest * Address CN and UI coverage test regressions * Fix Toolbar overflow command test
1 parent de71c18 commit 47558a4

File tree

4 files changed

+236
-30
lines changed

4 files changed

+236
-30
lines changed

maven/core-unittests/src/test/java/com/codename1/ui/CNTest.java

Lines changed: 56 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,49 +2,75 @@
22

33
import com.codename1.junit.FormTest;
44
import com.codename1.junit.UITestBase;
5-
import org.junit.jupiter.api.AfterEach;
6-
import org.junit.jupiter.api.Test;
5+
import com.codename1.ui.plaf.Style;
6+
7+
import java.util.concurrent.atomic.AtomicInteger;
78

89
import static org.junit.jupiter.api.Assertions.*;
9-
import static org.mockito.ArgumentMatchers.anyString;
10-
import static org.mockito.ArgumentMatchers.eq;
11-
import static org.mockito.Mockito.verify;
12-
import static org.mockito.Mockito.when;
1310

1411
class CNTest extends UITestBase {
1512

16-
@AfterEach
17-
void restoreFlags() {
18-
Component.revalidateOnStyleChange = true;
19-
}
20-
21-
@Test
22-
void testSetPropertyUpdatesComponentFlags() {
23-
CN.setProperty("Component.revalidateOnStyleChange", "false");
24-
assertFalse(Component.revalidateOnStyleChange);
13+
@FormTest
14+
void delegatesDisplayState() {
15+
Display display = Display.getInstance();
16+
Form current = display.getCurrent();
17+
current.removeAll();
18+
current.setTitle("CN Proxy Test");
19+
CN.setProperty("proxyKey", "proxyValue");
2520

26-
CN.setProperty("Component.revalidateOnStyleChange", "true");
27-
assertTrue(Component.revalidateOnStyleChange);
21+
assertSame(current, CN.getCurrentForm());
22+
assertEquals(display.getDisplayWidth(), CN.getDisplayWidth());
23+
assertEquals(display.getDisplayHeight(), CN.getDisplayHeight());
24+
assertEquals("proxyValue", display.getProperty("proxyKey", null));
25+
assertEquals(display.convertToPixels(3, true), CN.convertToPixels(3, true));
26+
assertEquals(display.convertToPixels(2.5f, Style.UNIT_TYPE_DIPS, true), CN.convertToPixels(2.5f, Style.UNIT_TYPE_DIPS, true));
27+
assertEquals(display.getDeviceDensity(), CN.getDeviceDensity());
28+
assertEquals(display.isPortrait(), CN.isPortrait());
2829
}
2930

3031
@FormTest
31-
void testRequestFullScreenDelegatesToImplementation() {
32-
if(CN.isFullScreenSupported()) {
33-
assertTrue(CN.requestFullScreen());
34-
assertTrue(CN.isInFullScreenMode());
32+
void bookmarkAndSerialCallsExecute() {
33+
AtomicInteger invoked = new AtomicInteger();
34+
CN.setBookmark(invoked::incrementAndGet);
35+
CN.restoreToBookmark();
36+
assertEquals(1, invoked.get(), "Bookmark runnable should be invoked on restore");
37+
38+
invoked.set(0);
39+
CN.callSerially(invoked::incrementAndGet);
40+
flushSerialCalls();
41+
assertEquals(1, invoked.get(), "callSerially should enqueue runnable on EDT");
42+
43+
RuntimeException thrown = null;
44+
try {
45+
CN.callSeriallyAndWait(new Runnable() {
46+
@Override
47+
public void run() {
48+
invoked.incrementAndGet();
49+
}
50+
});
51+
fail("callSeriallyAndWait should not be allowed on the EDT");
52+
} catch (RuntimeException ex) {
53+
thrown = ex;
3554
}
55+
assertNotNull(thrown, "Exception should be thrown when callSeriallyAndWait runs on the EDT");
56+
assertTrue(thrown.getMessage().contains("MUST NOT"), "Exception message should indicate EDT restriction");
57+
assertEquals(1, invoked.get(), "Runnable executes immediately even though the method throws on the EDT");
3658
}
3759

3860
@FormTest
39-
void testCanExecuteDelegatesToImplementation() {
40-
assertTrue(CN.canExecute("scheme:test"));
41-
}
61+
void invokeBlocksAndReturnsResult() {
62+
AtomicInteger invoked = new AtomicInteger();
63+
CN.invokeAndBlock(new Runnable() {
64+
@Override
65+
public void run() {
66+
invoked.incrementAndGet();
67+
}
68+
});
69+
assertEquals(1, invoked.get(), "invokeAndBlock should execute runnable synchronously");
4270

43-
@FormTest
44-
void testPropertyAndDisplayAccessors() {
45-
implementation.putProperty("key", "value");
46-
assertEquals("value", CN.getProperty("key", "default"));
47-
assertEquals(implementation.getDisplayWidth(), CN.getDisplayWidth());
48-
assertEquals(implementation.getDisplayHeight(), CN.getDisplayHeight());
71+
final AtomicInteger resultHolder = new AtomicInteger();
72+
Integer result = CN.invokeWithoutBlockingWithResultSync(resultHolder::incrementAndGet);
73+
assertEquals(1, resultHolder.get());
74+
assertEquals(Integer.valueOf(1), result);
4975
}
5076
}

maven/core-unittests/src/test/java/com/codename1/ui/ComponentSelectorTest.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,4 +210,48 @@ void testSelectFromCurrentForm() {
210210
ComponentSelector selector = ComponentSelector.$("CurrentFormLabel");
211211
assertEquals(1, selector.size());
212212
}
213+
214+
@FormTest
215+
void testStyleModeSelection() {
216+
Form form = Display.getInstance().getCurrent();
217+
form.removeAll();
218+
form.setLayout(BoxLayout.y());
219+
220+
Button button = new Button("Stylable");
221+
button.setUIID("Stylable");
222+
form.add(button);
223+
form.revalidate();
224+
225+
ComponentSelector selector = ComponentSelector.$("Stylable", form);
226+
selector.selectPressedStyle().setFgColor(0xff0000);
227+
selector.selectUnselectedStyle().setBgColor(0x00ff00);
228+
selector.selectDisabledStyle().setBgTransparency(200);
229+
230+
assertEquals(0xff0000, button.getPressedStyle().getFgColor());
231+
assertEquals(0x00ff00, button.getUnselectedStyle().getBgColor());
232+
assertEquals(200, button.getDisabledStyle().getBgTransparency() & 0xff);
233+
}
234+
235+
@FormTest
236+
void testMultipleSelectorsWithTags() {
237+
Form form = Display.getInstance().getCurrent();
238+
form.removeAll();
239+
form.setLayout(BoxLayout.y());
240+
241+
Button tagged = new Button("Tagged");
242+
tagged.setUIID("Tagged");
243+
ComponentSelector.$(tagged).addTags("primary", "action");
244+
245+
Label untagged = new Label("Plain");
246+
untagged.setUIID("Plain");
247+
form.addAll(tagged, untagged);
248+
form.revalidate();
249+
250+
ComponentSelector taggedSelector = ComponentSelector.$(".primary", form);
251+
assertEquals(1, taggedSelector.size());
252+
taggedSelector.setText("Updated");
253+
254+
assertEquals("Updated", tagged.getText());
255+
assertEquals("Plain", untagged.getText());
256+
}
213257
}

maven/core-unittests/src/test/java/com/codename1/ui/DialogTest.java

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,69 @@ void timeoutDisposesDialogDuringAnimation() {
8787
assertTrue(dialog.isDisposed(), "Dialog should be disposed after timeout");
8888
}
8989

90+
@FormTest
91+
void staticConfigurationCarriesToNewDialogs() {
92+
boolean originalAutoAdjust = Dialog.isAutoAdjustDialogSize();
93+
String originalPosition = Dialog.getDefaultDialogPosition();
94+
boolean originalScrolling = Dialog.isDisableStaticDialogScrolling();
95+
boolean originalCommandsAsButtons = Dialog.isCommandsAsButtons();
96+
boolean originalDispose = Dialog.isDefaultDisposeWhenPointerOutOfBounds();
97+
float originalBlurRadius = Dialog.getDefaultBlurBackgroundRadius();
98+
99+
try {
100+
Dialog.setAutoAdjustDialogSize(false);
101+
Dialog.setDefaultDialogPosition(BorderLayout.SOUTH);
102+
Dialog.setDisableStaticDialogScrolling(true);
103+
Dialog.setCommandsAsButtons(false);
104+
Dialog.setDefaultDisposeWhenPointerOutOfBounds(true);
105+
Dialog.setDefaultBlurBackgroundRadius(4.5f);
106+
107+
Dialog dialog = new Dialog("Configured", new BorderLayout());
108+
dialog.getContentPane().addComponent(BorderLayout.CENTER, new Label("Body"));
109+
110+
assertFalse(Dialog.isAutoAdjustDialogSize());
111+
assertTrue(Dialog.isDisableStaticDialogScrolling());
112+
assertFalse(Dialog.isCommandsAsButtons());
113+
assertTrue(Dialog.isDefaultDisposeWhenPointerOutOfBounds());
114+
assertEquals(BorderLayout.SOUTH, dialog.getDialogPosition());
115+
assertTrue(dialog.isDisposeWhenPointerOutOfBounds());
116+
assertEquals(4.5f, dialog.getBlurBackgroundRadius(), 0.01f);
117+
} finally {
118+
Dialog.setAutoAdjustDialogSize(originalAutoAdjust);
119+
Dialog.setDefaultDialogPosition(originalPosition);
120+
Dialog.setDisableStaticDialogScrolling(originalScrolling);
121+
Dialog.setCommandsAsButtons(originalCommandsAsButtons);
122+
Dialog.setDefaultDisposeWhenPointerOutOfBounds(originalDispose);
123+
Dialog.setDefaultBlurBackgroundRadius(originalBlurRadius);
124+
}
125+
}
126+
127+
@FormTest
128+
void popupDialogCanBeDisposedFromBackground() throws Exception {
129+
implementation.setBuiltinSoundsEnabled(false);
130+
Dialog dialog = new Dialog("Popup", new BorderLayout());
131+
Label body = new Label("Popup Body");
132+
dialog.getContentPane().addComponent(BorderLayout.CENTER, body);
133+
dialog.setDisposeWhenPointerOutOfBounds(true);
134+
135+
Thread disposer = new Thread(new Runnable() {
136+
@Override
137+
public void run() {
138+
try {
139+
Thread.sleep(50L);
140+
} catch (InterruptedException ignored) {
141+
}
142+
dialog.dispose();
143+
}
144+
});
145+
disposer.start();
146+
147+
dialog.showPopupDialog(body);
148+
disposer.join(1000L);
149+
150+
assertTrue(dialog.isDisposed(), "Popup dialog should dispose when closed from another thread");
151+
}
152+
90153
private Button findButton(Container root, Command target) {
91154
for (int i = 0; i < root.getComponentCount(); i++) {
92155
Component cmp = root.getComponentAt(i);

maven/core-unittests/src/test/java/com/codename1/ui/ToolbarTest.java

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,4 +134,77 @@ void rightBarCommandsAndTitleComponentCustomization() {
134134
toolbar.removeCommand(right);
135135
assertNull(toolbar.findCommandComponent(right), "Removed command should no longer have a button");
136136
}
137+
138+
@FormTest
139+
void rightSideMenuCommandsDispatch() {
140+
implementation.setBuiltinSoundsEnabled(false);
141+
Toolbar.setOnTopSideMenu(true);
142+
143+
Form form = new Form(new BorderLayout());
144+
Toolbar toolbar = new Toolbar();
145+
form.setToolbar(toolbar);
146+
form.show();
147+
form.getAnimationManager().flush();
148+
flushSerialCalls();
149+
150+
final int[] invocation = {0};
151+
Command rightSide = toolbar.addCommandToRightSideMenu("RightMenu", null, evt -> invocation[0]++);
152+
153+
toolbar.openRightSideMenu();
154+
form.getAnimationManager().flush();
155+
flushSerialCalls();
156+
awaitAnimations(form);
157+
158+
Button rightButton = toolbar.findCommandComponent(rightSide);
159+
assertNotNull(rightButton, "Right side menu button should be created");
160+
161+
int px = rightButton.getAbsoluteX() + rightButton.getWidth() / 2;
162+
int py = rightButton.getAbsoluteY() + rightButton.getHeight() / 2;
163+
rightButton.pointerPressed(px, py);
164+
rightButton.pointerReleased(px, py);
165+
flushSerialCalls();
166+
167+
assertEquals(1, invocation[0], "Pointer events should fire right side menu command");
168+
169+
toolbar.closeRightSideMenu();
170+
form.getAnimationManager().flush();
171+
flushSerialCalls();
172+
awaitAnimations(form);
173+
}
174+
175+
@FormTest
176+
void sideMenuAndOverflowCommands() {
177+
implementation.setBuiltinSoundsEnabled(false);
178+
Display.getInstance().setCommandBehavior(Display.COMMAND_BEHAVIOR_SIDE_NAVIGATION);
179+
Toolbar.setOnTopSideMenu(true);
180+
181+
Form form = new Form(new BorderLayout());
182+
Toolbar toolbar = new Toolbar();
183+
form.setToolbar(toolbar);
184+
form.show();
185+
form.getAnimationManager().flush();
186+
flushSerialCalls();
187+
188+
final int[] sideInvocation = {0};
189+
final int[] overflowInvocation = {0};
190+
Command side = toolbar.addCommandToSideMenu("Side", null, evt -> sideInvocation[0]++);
191+
Command overflow = toolbar.addCommandToOverflowMenu("Overflow", null, evt -> overflowInvocation[0]++);
192+
193+
toolbar.openSideMenu();
194+
form.getAnimationManager().flush();
195+
flushSerialCalls();
196+
awaitAnimations(form);
197+
198+
Button sideButton = toolbar.findCommandComponent(side);
199+
assertNotNull(sideButton, "Side menu should create a button for the command");
200+
side.actionPerformed(new ActionEvent(side));
201+
flushSerialCalls();
202+
203+
assertEquals(1, sideInvocation[0], "Side menu command should fire its listener");
204+
205+
overflow.actionPerformed(new ActionEvent(overflow));
206+
flushSerialCalls();
207+
208+
assertEquals(1, overflowInvocation[0], "Overflow command should be invoked");
209+
}
137210
}

0 commit comments

Comments
 (0)