Skip to content

Commit 3327c42

Browse files
Improve unit test coverage for core classes (#4241)
Added LoginTest to cover Login inner classes. Updated FacebookConnectTest to test validateToken and cover connection request logic. Updated JSObjectTest to cover async calls with SuccessCallback. Updated ValidatorTest to cover scroll listener logic. Updated TestCodenameOneImplementation to support network mocking. Updated PickerTest to clarify coverage of inner classes. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
1 parent 8a567b3 commit 3327c42

File tree

6 files changed

+266
-0
lines changed

6 files changed

+266
-0
lines changed

maven/core-unittests/src/test/java/com/codename1/javascript/JSObjectTest.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,45 @@ void callAsyncDelegatesToJavascriptContext() {
210210
assertArrayEquals(new Object[]{}, context.removeNextParams());
211211
}
212212

213+
@Test
214+
void callStringAsyncDelegatesToJavascriptContext() {
215+
responses.add("ignored");
216+
responses.add("object");
217+
responses.add("11");
218+
RecordingJavascriptContext context = createContextSpy();
219+
JSObject object = new JSObject(context, "window");
220+
221+
SuccessCallback<String> successCallback = mock(SuccessCallback.class);
222+
223+
object.callStringAsync("action", successCallback);
224+
225+
verify(context).callAsync(eq(object), eq(object), any(Object[].class), any(Callback.class));
226+
227+
Callback callback = context.removeNextCallback();
228+
callback.onSucess("result");
229+
verify(successCallback).onSucess("result");
230+
}
231+
232+
@Test
233+
void callObjectAsyncDelegatesToJavascriptContext() {
234+
responses.add("ignored");
235+
responses.add("object");
236+
responses.add("12");
237+
RecordingJavascriptContext context = createContextSpy();
238+
JSObject object = new JSObject(context, "window");
239+
240+
SuccessCallback<JSObject> successCallback = mock(SuccessCallback.class);
241+
242+
object.callObjectAsync("action", successCallback);
243+
244+
verify(context).callAsync(eq(object), eq(object), any(Object[].class), any(Callback.class));
245+
246+
Callback callback = context.removeNextCallback();
247+
JSObject result = mock(JSObject.class);
248+
callback.onSucess(result);
249+
verify(successCallback).onSucess(result);
250+
}
251+
213252
@Test
214253
void removeCallbackDelegatesToContext() {
215254
responses.add("ignored");

maven/core-unittests/src/test/java/com/codename1/social/FacebookConnectTest.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.codename1.io.Storage;
77
import com.codename1.junit.FormTest;
88
import com.codename1.junit.UITestBase;
9+
import com.codename1.testing.TestCodenameOneImplementation;
910
import com.codename1.testing.TestCodenameOneImplementation.TestConnection;
1011

1112
import org.junit.jupiter.api.AfterEach;
@@ -35,6 +36,7 @@ void setUpFacebookConnect() {
3536
void tearDownFacebookConnect() {
3637
clearStoredCredentials();
3738
implementation.clearConnections();
39+
implementation.clearNetworkMocks();
3840
FaceBookAccess.setToken(null);
3941
}
4042

@@ -123,6 +125,18 @@ void unsupportedOperationsThrowRuntimeExceptions() {
123125
assertThrows(RuntimeException.class, new FacebookConnect()::hasPublishPermissions);
124126
}
125127

128+
@FormTest
129+
public void testValidateToken() {
130+
TestCodenameOneImplementation.getInstance().addNetworkMockResponse("https://graph.facebook.com/v2.4/me", 400, "Bad Request", null);
131+
132+
boolean result = connect.validateToken("invalid_token");
133+
assertFalse(result, "Should return false on 400 response");
134+
135+
TestCodenameOneImplementation.getInstance().addNetworkMockResponse("https://graph.facebook.com/v2.4/me", 200, "OK", null);
136+
result = connect.validateToken("valid_token");
137+
assertTrue(result, "Should return true on 200 response");
138+
}
139+
126140
private void clearStoredCredentials() {
127141
Storage.getInstance().deleteStorageFile(FacebookConnect.class.getName() + "AccessToken");
128142
Preferences.delete(FacebookConnect.class.getName() + "Token");
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
package com.codename1.social;
2+
3+
import com.codename1.io.AccessToken;
4+
import com.codename1.junit.FormTest;
5+
import com.codename1.junit.UITestBase;
6+
import com.codename1.ui.CN;
7+
import com.codename1.util.AsyncResource;
8+
import org.junit.jupiter.api.Test;
9+
10+
import java.io.IOException;
11+
import java.util.concurrent.atomic.AtomicBoolean;
12+
13+
import static org.junit.jupiter.api.Assertions.*;
14+
15+
public class LoginTest extends UITestBase {
16+
17+
static class TestLogin extends Login {
18+
boolean validateTokenResult = true;
19+
boolean nativeLoginSupported = false;
20+
21+
@Override
22+
public boolean isNativeLoginSupported() {
23+
return nativeLoginSupported;
24+
}
25+
26+
@Override
27+
public void doLogin() {
28+
// Simulate login process started
29+
}
30+
31+
@Override
32+
protected boolean validateToken(String token) {
33+
return validateTokenResult;
34+
}
35+
}
36+
37+
@FormTest
38+
public void testLoginCallbackProxy() throws Exception {
39+
TestLogin login = new TestLogin();
40+
// Setup fields to avoid validation errors
41+
login.setClientId("id");
42+
login.setClientSecret("secret");
43+
login.setOauth2URL("url");
44+
login.setRedirectURI("uri");
45+
login.setAccessToken(new AccessToken("token", null));
46+
47+
AtomicBoolean successCalled = new AtomicBoolean(false);
48+
AtomicBoolean failedCalled = new AtomicBoolean(false);
49+
50+
LoginCallback cb = new LoginCallback() {
51+
@Override
52+
public void loginSuccessful() {
53+
successCalled.set(true);
54+
}
55+
56+
@Override
57+
public void loginFailed(String errorMessage) {
58+
failedCalled.set(true);
59+
}
60+
};
61+
62+
// Register callback via doLogin
63+
login.doLogin(cb);
64+
65+
// Access package-private callback proxy
66+
final LoginCallback proxy = login.callback;
67+
assertNotNull(proxy);
68+
69+
// Trigger success from background thread (to force callSerially)
70+
Thread t = new Thread(() -> {
71+
proxy.loginSuccessful();
72+
});
73+
t.start();
74+
t.join();
75+
76+
flushSerialCalls();
77+
assertTrue(successCalled.get());
78+
79+
// Test failure
80+
login.doLogin(cb);
81+
Thread t2 = new Thread(() -> {
82+
proxy.loginFailed("Error");
83+
});
84+
t2.start();
85+
t2.join();
86+
87+
flushSerialCalls();
88+
assertTrue(failedCalled.get());
89+
}
90+
91+
@FormTest
92+
public void testConnect() {
93+
TestLogin login = new TestLogin();
94+
login.setClientId("id");
95+
login.setClientSecret("secret");
96+
login.setOauth2URL("url");
97+
login.setRedirectURI("uri");
98+
login.setAccessToken(new AccessToken("token", null));
99+
100+
// Mock doLogin to immediately succeed
101+
login = new TestLogin() {
102+
@Override
103+
public void doLogin() {
104+
callback.loginSuccessful();
105+
}
106+
};
107+
// Need to set fields again on new instance
108+
login.setClientId("id");
109+
login.setClientSecret("secret");
110+
login.setOauth2URL("url");
111+
login.setRedirectURI("uri");
112+
login.setAccessToken(new AccessToken("token", null));
113+
114+
AsyncResource<Login> res = login.connect();
115+
assertNotNull(res.get());
116+
assertEquals(login, res.get());
117+
}
118+
119+
@FormTest
120+
public void testValidateTokenWaitsForLogin() throws Exception {
121+
TestLogin login = new TestLogin() {
122+
@Override
123+
public void doLogin() {
124+
// Simulate async login
125+
new Thread(() -> {
126+
try {
127+
Thread.sleep(50);
128+
} catch (InterruptedException e) {}
129+
// Complete login
130+
if (!CN.isEdt()) {
131+
CN.callSerially(() -> callback.loginSuccessful());
132+
} else {
133+
callback.loginSuccessful();
134+
}
135+
}).start();
136+
}
137+
};
138+
login.validateTokenResult = false;
139+
login.setClientId("id");
140+
login.setClientSecret("secret");
141+
login.setOauth2URL("url");
142+
login.setRedirectURI("uri");
143+
login.setAccessToken(new AccessToken("token", null));
144+
145+
// validateToken should block until doLogin completes
146+
login.validateToken();
147+
// If it returns, it means it waited and succeeded.
148+
}
149+
}

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,27 @@ public class TestCodenameOneImplementation extends CodenameOneImplementation {
193193
private Function<String, byte[]> connectionResponseProvider;
194194
private final Map<String, String[]> sslCertificatesByUrl = new ConcurrentHashMap<String, String[]>();
195195
private boolean sslCertificatesSupported;
196+
private final Map<String, MockResponse> mockResponses = new ConcurrentHashMap<String, MockResponse>();
197+
198+
public static class MockResponse {
199+
int code;
200+
String message;
201+
byte[] body;
202+
203+
public MockResponse(int code, String message, byte[] body) {
204+
this.code = code;
205+
this.message = message;
206+
this.body = body;
207+
}
208+
}
209+
210+
public void addNetworkMockResponse(String url, int code, String message, byte[] body) {
211+
mockResponses.put(url, new MockResponse(code, message, body));
212+
}
213+
214+
public void clearNetworkMocks() {
215+
mockResponses.clear();
216+
}
196217

197218

198219
public TestCodenameOneImplementation() {
@@ -1959,6 +1980,17 @@ public Object connect(String url, boolean read, boolean write) throws IOExceptio
19591980
connection.setContentLength(response.length);
19601981
}
19611982
}
1983+
for (Map.Entry<String, MockResponse> entry : mockResponses.entrySet()) {
1984+
if (url.startsWith(entry.getKey())) {
1985+
MockResponse r = entry.getValue();
1986+
connection.setResponseCode(r.code);
1987+
connection.setResponseMessage(r.message);
1988+
if (r.body != null) {
1989+
connection.setInputData(r.body);
1990+
connection.setContentLength(r.body.length);
1991+
}
1992+
}
1993+
}
19621994
return connection;
19631995
}
19641996

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,4 +182,7 @@ public void testPickerResizeUpdatesDialog() {
182182
f.animate();
183183
flushSerialCalls();
184184
}
185+
186+
// Note: Picker$3$1 (runnable in sizeChanged listener) is covered by testPickerResizeUpdatesDialog
187+
// Picker$1$8 (Cancel command in showDialog) is unreachable dead code for standard types.
185188
}

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.codename1.ui.Label;
99
import com.codename1.ui.TextComponent;
1010
import com.codename1.ui.TextField;
11+
import com.codename1.ui.TextArea;
1112
import com.codename1.ui.layouts.BoxLayout;
1213
import com.codename1.ui.plaf.UIManager;
1314

@@ -151,6 +152,34 @@ void testShowErrorMessageForFocusedComponent() {
151152
// Verifying the actual popup is hard as it is UI side effect.
152153
}
153154

155+
@FormTest
156+
void testShowErrorMessageScrollListener() {
157+
Form form = new Form(new BoxLayout(BoxLayout.Y_AXIS));
158+
TextArea ta = new TextArea("abc"); // Invalid content
159+
ta.setSingleLineTextArea(false);
160+
ta.setRows(5);
161+
form.add(ta);
162+
form.show();
163+
164+
Validator validator = new Validator();
165+
validator.setShowErrorMessageForFocusedComponent(true);
166+
// Force highlight mode to EMBLEM to trigger the scroll listener addition logic
167+
validator.setValidationFailureHighlightMode(Validator.HighlightMode.EMBLEM);
168+
169+
validator.addConstraint(ta, new LengthConstraint(5, "Too short"));
170+
171+
// Trigger focus gained on the component
172+
ta.requestFocus();
173+
174+
// This should show the popup message and add ScrollListener.
175+
176+
// Now simulate scroll
177+
Component scrollable = ta.getScrollable();
178+
if (scrollable != null) {
179+
scrollable.scrollRectToVisible(10, 0, 10, 10, ta);
180+
}
181+
}
182+
154183
@FormTest
155184
public void testValidationErrorMessage() {
156185
// Enable option

0 commit comments

Comments
 (0)