Skip to content

Commit 40e723b

Browse files
authored
Add UI component unit tests for dialogs and sheets (#4109)
* Add comprehensive UI component tests * Fix Dialog test compilation imports * Fixed unit tests
1 parent d00c465 commit 40e723b

File tree

6 files changed

+660
-0
lines changed

6 files changed

+660
-0
lines changed
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
package com.codename1.ui;
2+
3+
import com.codename1.junit.FormTest;
4+
import com.codename1.junit.UITestBase;
5+
import com.codename1.ui.Button;
6+
import com.codename1.ui.Component;
7+
import com.codename1.ui.Container;
8+
import com.codename1.ui.layouts.BorderLayout;
9+
10+
import java.util.ArrayList;
11+
import java.util.Calendar;
12+
import java.util.Collection;
13+
import java.util.Date;
14+
import java.util.List;
15+
16+
import static org.junit.jupiter.api.Assertions.*;
17+
18+
class CalendarTest extends UITestBase {
19+
20+
@FormTest
21+
void selectingDayUpdatesSelectedDate() {
22+
implementation.setBuiltinSoundsEnabled(false);
23+
Form form = Display.getInstance().getCurrent();
24+
form.setLayout(new BorderLayout());
25+
26+
com.codename1.ui.Calendar widget = new com.codename1.ui.Calendar();
27+
form.add(BorderLayout.CENTER, widget);
28+
form.revalidate();
29+
30+
Calendar cal = Calendar.getInstance();
31+
cal.set(2022, Calendar.APRIL, 15, 0, 0, 0);
32+
cal.set(Calendar.MILLISECOND, 0);
33+
widget.setDate(cal.getTime());
34+
form.revalidate();
35+
36+
Button target = findDayButton(widget, 20);
37+
assertNotNull(target, "Expected to find button for day 20");
38+
39+
int x = target.getAbsoluteX() + target.getWidth() / 2;
40+
int y = target.getAbsoluteY() + target.getHeight() / 2;
41+
target.pointerPressed(x, y);
42+
target.pointerReleased(x, y);
43+
44+
Date selected = widget.getDate();
45+
Calendar selectedCal = Calendar.getInstance();
46+
selectedCal.setTime(selected);
47+
assertEquals(20, selectedCal.get(Calendar.DAY_OF_MONTH), "Selecting day button should update selected date");
48+
}
49+
50+
@FormTest
51+
void disablingSelectionPreventsDateChanges() {
52+
implementation.setBuiltinSoundsEnabled(false);
53+
Form form = Display.getInstance().getCurrent();
54+
form.setLayout(new BorderLayout());
55+
56+
com.codename1.ui.Calendar widget = new com.codename1.ui.Calendar();
57+
widget.setChangesSelectedDateEnabled(false);
58+
form.add(BorderLayout.CENTER, widget);
59+
form.revalidate();
60+
61+
Calendar cal = Calendar.getInstance();
62+
cal.set(2023, Calendar.JANUARY, 5, 0, 0, 0);
63+
cal.set(Calendar.MILLISECOND, 0);
64+
widget.setDate(cal.getTime());
65+
form.revalidate();
66+
67+
Date original = widget.getDate();
68+
69+
Button target = findDayButton(widget, 10);
70+
assertNotNull(target, "Expected to find day button");
71+
72+
int x = target.getAbsoluteX() + target.getWidth() / 2;
73+
int y = target.getAbsoluteY() + target.getHeight() / 2;
74+
target.pointerPressed(x, y);
75+
target.pointerReleased(x, y);
76+
77+
assertEquals(original, widget.getDate(), "Date should remain unchanged when selection disabled");
78+
}
79+
80+
@FormTest
81+
void multipleSelectionTracksAllSelectedDays() {
82+
implementation.setBuiltinSoundsEnabled(false);
83+
Form form = Display.getInstance().getCurrent();
84+
form.setLayout(new BorderLayout());
85+
86+
com.codename1.ui.Calendar widget = new com.codename1.ui.Calendar();
87+
widget.setMultipleSelectionEnabled(true);
88+
form.add(BorderLayout.CENTER, widget);
89+
form.revalidate();
90+
91+
Calendar cal = Calendar.getInstance();
92+
cal.set(2021, Calendar.AUGUST, 1, 0, 0, 0);
93+
cal.set(Calendar.MILLISECOND, 0);
94+
widget.setDate(cal.getTime());
95+
form.revalidate();
96+
97+
Button day5 = findDayButton(widget, 5);
98+
Button day7 = findDayButton(widget, 7);
99+
assertNotNull(day5, "Expected day 5 button");
100+
assertNotNull(day7, "Expected day 7 button");
101+
102+
pressButton(day5);
103+
pressButton(day7);
104+
105+
Collection<Date> selectedDays = widget.getSelectedDays();
106+
assertNotNull(selectedDays, "Selected days collection should not be null");
107+
assertEquals(2, selectedDays.size(), "Two days should be selected");
108+
109+
List<Integer> dayValues = new ArrayList<>();
110+
for (Date d : selectedDays) {
111+
Calendar c = Calendar.getInstance();
112+
c.setTime(d);
113+
dayValues.add(c.get(Calendar.DAY_OF_MONTH));
114+
}
115+
assertTrue(dayValues.contains(5), "Selected days should include 5");
116+
assertTrue(dayValues.contains(7), "Selected days should include 7");
117+
}
118+
119+
private void pressButton(Button button) {
120+
int x = button.getAbsoluteX() + button.getWidth() / 2;
121+
int y = button.getAbsoluteY() + button.getHeight() / 2;
122+
button.pointerPressed(x, y);
123+
button.pointerReleased(x, y);
124+
}
125+
126+
private Button findDayButton(com.codename1.ui.Calendar calendar, int day) {
127+
Container monthView = (Container) calendar.getComponentAt(calendar.getComponentCount() - 1);
128+
Container days = (Container) monthView.getComponentAt(1);
129+
for (int i = 0; i < days.getComponentCount(); i++) {
130+
Component cmp = days.getComponentAt(i);
131+
if (cmp instanceof Button) {
132+
Button button = (Button) cmp;
133+
if (button.isEnabled()) {
134+
String text = button.getText();
135+
if (text != null && text.trim().equals(String.valueOf(day))) {
136+
return button;
137+
}
138+
}
139+
}
140+
}
141+
return null;
142+
}
143+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package com.codename1.ui;
2+
3+
import com.codename1.junit.FormTest;
4+
import com.codename1.junit.UITestBase;
5+
import com.codename1.ui.Button;
6+
import com.codename1.ui.Command;
7+
import com.codename1.ui.Container;
8+
import com.codename1.ui.Label;
9+
import com.codename1.ui.layouts.BorderLayout;
10+
11+
import static org.junit.jupiter.api.Assertions.*;
12+
13+
class DialogTest extends UITestBase {
14+
15+
@FormTest
16+
void disposeWhenPointerOutOfBoundsClosesDialog() {
17+
implementation.setBuiltinSoundsEnabled(false);
18+
Form form = Display.getInstance().getCurrent();
19+
20+
Dialog dialog = new Dialog("Outside", new BorderLayout());
21+
dialog.getContentPane().addComponent(BorderLayout.CENTER, new Label("Body"));
22+
dialog.setDisposeWhenPointerOutOfBounds(true);
23+
dialog.showModeless();
24+
25+
form.getAnimationManager().flush();
26+
form.revalidate();
27+
28+
int outsideX = dialog.getAbsoluteX() - 10;
29+
int outsideY = dialog.getAbsoluteY() - 10;
30+
dialog.pointerPressed(outsideX, outsideY);
31+
dialog.pointerReleased(outsideX, outsideY);
32+
form.getAnimationManager().flush();
33+
34+
assertTrue(dialog.isDisposed(), "Dialog should dispose when pointer released outside bounds");
35+
}
36+
37+
@FormTest
38+
void commandButtonsDispatchActions() {
39+
implementation.setBuiltinSoundsEnabled(false);
40+
Form form = Display.getInstance().getCurrent();
41+
boolean originalCommandsAsButtons = Dialog.isCommandsAsButtons();
42+
Dialog.setCommandsAsButtons(true);
43+
44+
Dialog dialog = new Dialog("Commands", new BorderLayout());
45+
dialog.getContentPane().addComponent(BorderLayout.CENTER, new Label("Body"));
46+
47+
Command ok = new Command("OK");
48+
Command cancel = new Command("Cancel");
49+
dialog.placeButtonCommands(new Command[]{ok, cancel});
50+
51+
final Command[] executed = new Command[1];
52+
dialog.addCommandListener(evt -> executed[0] = evt.getCommand());
53+
54+
dialog.showModeless();
55+
form.getAnimationManager().flush();
56+
form.revalidate();
57+
58+
Button okButton = findButton(dialog, ok);
59+
assertNotNull(okButton, "OK button should be created for command");
60+
61+
int px = okButton.getAbsoluteX() + okButton.getWidth() / 2;
62+
int py = okButton.getAbsoluteY() + okButton.getHeight() / 2;
63+
dialog.pointerPressed(px, py);
64+
okButton.pointerPressed(px, py);
65+
okButton.pointerReleased(px, py);
66+
dialog.pointerReleased(px, py);
67+
68+
assertSame(ok, executed[0], "OK command should be dispatched when button is pressed");
69+
70+
dialog.dispose();
71+
Dialog.setCommandsAsButtons(originalCommandsAsButtons);
72+
}
73+
74+
@FormTest
75+
void timeoutDisposesDialogDuringAnimation() {
76+
implementation.setBuiltinSoundsEnabled(false);
77+
Form form = Display.getInstance().getCurrent();
78+
79+
Dialog dialog = new Dialog("Timeout", new BorderLayout());
80+
dialog.getContentPane().addComponent(BorderLayout.CENTER, new Label("Body"));
81+
dialog.showModeless();
82+
form.getAnimationManager().flush();
83+
84+
dialog.setTimeout(0);
85+
dialog.animate();
86+
87+
assertTrue(dialog.isDisposed(), "Dialog should be disposed after timeout");
88+
}
89+
90+
private Button findButton(Container root, Command target) {
91+
for (int i = 0; i < root.getComponentCount(); i++) {
92+
Component cmp = root.getComponentAt(i);
93+
if (cmp instanceof Button) {
94+
Button button = (Button) cmp;
95+
if (button.getCommand() == target) {
96+
return button;
97+
}
98+
}
99+
if (cmp instanceof Container) {
100+
Button found = findButton((Container) cmp, target);
101+
if (found != null) {
102+
return found;
103+
}
104+
}
105+
}
106+
return null;
107+
}
108+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package com.codename1.ui;
2+
3+
import com.codename1.junit.FormTest;
4+
import com.codename1.junit.UITestBase;
5+
import com.codename1.ui.Label;
6+
import com.codename1.ui.layouts.BorderLayout;
7+
8+
import java.util.concurrent.CountDownLatch;
9+
import java.util.concurrent.TimeUnit;
10+
11+
import static org.junit.jupiter.api.Assertions.*;
12+
13+
class SheetTest extends UITestBase {
14+
15+
@FormTest
16+
void showRegistersCurrentSheet() {
17+
implementation.setBuiltinSoundsEnabled(false);
18+
Form form = Display.getInstance().getCurrent();
19+
form.setLayout(new BorderLayout());
20+
21+
Sheet sheet = new Sheet(null, "Primary");
22+
sheet.getContentPane().add(new Label("Content"));
23+
sheet.show(0);
24+
form.getAnimationManager().flush();
25+
flushSerialCalls();
26+
27+
assertSame(sheet, Sheet.getCurrentSheet(), "Sheet should be current after showing");
28+
}
29+
30+
@FormTest
31+
void parentChildNavigationUpdatesCurrentSheet() {
32+
implementation.setBuiltinSoundsEnabled(false);
33+
Form form = Display.getInstance().getCurrent();
34+
form.setLayout(new BorderLayout());
35+
36+
Sheet parent = new Sheet(null, "Parent");
37+
Label parentLabel = new Label("Parent content");
38+
parent.getContentPane().add(parentLabel);
39+
parent.show(0);
40+
form.getAnimationManager().flush();
41+
flushSerialCalls();
42+
43+
Sheet child = new Sheet(parent, "Child");
44+
Label childLabel = new Label("Child content");
45+
child.getContentPane().add(childLabel);
46+
child.show(0);
47+
form.getAnimationManager().flush();
48+
flushSerialCalls();
49+
50+
child.back(0);
51+
awaitAnimations(form);
52+
53+
assertSame(parent, Sheet.getCurrentSheet(), "Parent sheet should be restored after child back()");
54+
assertSame(parent, Sheet.findContainingSheet(parentLabel), "findContainingSheet should locate parent sheet");
55+
}
56+
57+
private void awaitAnimations(Form form) {
58+
CountDownLatch latch = new CountDownLatch(1);
59+
form.getAnimationManager().flushAnimation(latch::countDown);
60+
form.getAnimationManager().flush();
61+
flushSerialCalls();
62+
try {
63+
latch.await(1, TimeUnit.SECONDS);
64+
} catch (InterruptedException e) {
65+
Thread.currentThread().interrupt();
66+
fail("Interrupted while waiting for animations to finish");
67+
}
68+
flushSerialCalls();
69+
}
70+
71+
@FormTest
72+
void allowCloseFlagCanBeToggled() {
73+
implementation.setBuiltinSoundsEnabled(false);
74+
Form form = Display.getInstance().getCurrent();
75+
form.setLayout(new BorderLayout());
76+
77+
Sheet sheet = new Sheet(null, "Configurable");
78+
sheet.getContentPane().add(new Label("Content"));
79+
sheet.setAllowClose(false);
80+
assertFalse(sheet.isAllowClose(), "Sheet should report allowClose=false when disabled");
81+
82+
sheet.setAllowClose(true);
83+
assertTrue(sheet.isAllowClose(), "Sheet should report allowClose=true when re-enabled");
84+
85+
form.getAnimationManager().flush();
86+
assertNull(Sheet.getCurrentSheet(), "No sheet should remain after backing out");
87+
}
88+
}

0 commit comments

Comments
 (0)