Skip to content

Commit 626a5e6

Browse files
committed
Extract BindingTestCase from RecordFactory
1 parent e0f8b4c commit 626a5e6

3 files changed

Lines changed: 161 additions & 148 deletions

File tree

api/src/org/labkey/api/ApiModule.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import org.labkey.api.data.AbstractForeignKey;
4747
import org.labkey.api.data.Aggregate;
4848
import org.labkey.api.data.AtomicDatabaseInteger;
49+
import org.labkey.api.data.BindingTestCase;
4950
import org.labkey.api.data.BooleanFormat;
5051
import org.labkey.api.data.BuilderObjectFactory;
5152
import org.labkey.api.data.CompareType;
@@ -508,6 +509,7 @@ public void registerServlets(ServletContext servletCtx)
508509
ApiKeyManager.TestCase.class,
509510
AppPropsTestCase.class,
510511
AtomicDatabaseInteger.TestCase.class,
512+
BindingTestCase.class,
511513
BlockingCache.BlockingCacheTest.class,
512514
CompareType.TestCase.class,
513515
ContainerDisplayColumn.TestCase.class,
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
package org.labkey.api.data;
2+
3+
import org.junit.Assert;
4+
import org.junit.Test;
5+
import org.labkey.api.action.BaseViewAction;
6+
import org.labkey.api.data.RecordFactory.MiniUser;
7+
import org.labkey.api.util.DateUtil;
8+
import org.springframework.beans.MutablePropertyValues;
9+
import org.springframework.beans.PropertyValues;
10+
import org.springframework.validation.BindException;
11+
import org.springframework.validation.ObjectError;
12+
13+
import java.util.Date;
14+
import java.util.Map;
15+
16+
public class BindingTestCase extends Assert
17+
{
18+
@Test
19+
public void testBinding()
20+
{
21+
Date lastLogin = new Date();
22+
23+
// Provide all parameters
24+
Map<String, Object> params = Map.of(
25+
"firstName", "Fred",
26+
"lastName", "Flintstone",
27+
"lastLogin", DateUtil.formatIsoDateLongTime(lastLogin),
28+
"userId", 1009
29+
);
30+
String toString = "MiniUser[FIRSTname=Fred, LASTNAME=Flintstone, lastLogin=" + lastLogin + ", UserId=1009]";
31+
testRecordBinding(params, toString);
32+
testFormBinding(params, toString);
33+
34+
// Provide just the primitive parameter; others are nullable
35+
params = Map.of(
36+
"userId", 1009
37+
);
38+
toString = "MiniUser[FIRSTname=null, LASTNAME=null, lastLogin=null, UserId=1009]";
39+
testRecordBinding(params, toString);
40+
testFormBinding(params, toString);
41+
42+
// No parameters should fail for record due to "userid" primitive. Ensure a reasonable error message.
43+
testRecordBinding(Map.of(), "Primitive parameter \"UserId\" is required");
44+
// No parameters should succeed for form class. UserId simply defaults to 0;
45+
testFormBinding(Map.of(), "MiniUser[FIRSTname=null, LASTNAME=null, lastLogin=null, UserId=0]");
46+
47+
// Verify message for conversion error
48+
params = Map.of("UserId", "abc");
49+
String errorMessage = "Failed to convert property value of type 'java.lang.String' to required type 'int' for property 'UserId'; Could not convert 'abc' to an integer";
50+
testRecordBinding(params, errorMessage);
51+
testFormBinding(params, errorMessage);
52+
}
53+
54+
private void testRecordBinding(Map<String, Object> map, String expectedToStringOrError)
55+
{
56+
PropertyValues pvs = new MutablePropertyValues(map);
57+
BindException be = BaseViewAction.bindParametersToRecord(MiniUser.class, pvs, "form");
58+
59+
if (be.hasErrors())
60+
{
61+
validateError(be, expectedToStringOrError);
62+
}
63+
else
64+
{
65+
validateTarget(be.getTarget(), expectedToStringOrError);
66+
}
67+
}
68+
69+
private void testFormBinding(Map<String, Object> map, String expectedToStringOrError)
70+
{
71+
PropertyValues pvs = new MutablePropertyValues(map);
72+
BindException be = BaseViewAction.defaultBindParameters(new MiniUserForm(), "form", pvs);
73+
74+
if (be.hasErrors())
75+
{
76+
validateError(be, expectedToStringOrError);
77+
}
78+
else
79+
{
80+
validateTarget(be.getTarget(), expectedToStringOrError);
81+
}
82+
}
83+
84+
private void validateError(BindException be, String expectedErrorMessage)
85+
{
86+
ObjectError error = be.getAllErrors().getFirst();
87+
assertNotNull(error);
88+
assertEquals(expectedErrorMessage, error.getDefaultMessage());
89+
}
90+
91+
private void validateTarget(Object user, String expectedToString)
92+
{
93+
assertNotNull(user);
94+
assertEquals(expectedToString, user.toString());
95+
}
96+
97+
// Simple test form
98+
@SuppressWarnings("unused")
99+
private static class MiniUserForm
100+
{
101+
String _firstName;
102+
String _lastName;
103+
Date _lastLogin;
104+
int _userId;
105+
106+
public String getFirstName()
107+
{
108+
return _firstName;
109+
}
110+
111+
public void setFirstName(String firstName)
112+
{
113+
_firstName = firstName;
114+
}
115+
116+
public String getLastName()
117+
{
118+
return _lastName;
119+
}
120+
121+
public void setLastName(String lastName)
122+
{
123+
_lastName = lastName;
124+
}
125+
126+
public Date getLastLogin()
127+
{
128+
return _lastLogin;
129+
}
130+
131+
public void setLastLogin(Date lastLogin)
132+
{
133+
_lastLogin = lastLogin;
134+
}
135+
136+
public int getUserId()
137+
{
138+
return _userId;
139+
}
140+
141+
public void setUserId(int userId)
142+
{
143+
_userId = userId;
144+
}
145+
146+
@Override
147+
public String toString()
148+
{
149+
// No useful default toString(), so emulate the standard record toString(). That's good enough to verify
150+
// that the parameters were bound correctly.
151+
return "MiniUser[FIRSTname=" + _firstName + ", LASTNAME=" + _lastName + ", lastLogin=" + _lastLogin + ", UserId=" + _userId + "]";
152+
}
153+
}
154+
}

api/src/org/labkey/api/data/RecordFactory.java

Lines changed: 5 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,11 @@
2020
import org.jetbrains.annotations.Nullable;
2121
import org.junit.Assert;
2222
import org.junit.Test;
23-
import org.labkey.api.action.BaseViewAction;
2423
import org.labkey.api.collections.CaseInsensitiveCollection;
2524
import org.labkey.api.collections.CaseInsensitiveHashMap;
2625
import org.labkey.api.collections.RowMap;
2726
import org.labkey.api.query.FieldKey;
28-
import org.labkey.api.util.DateUtil;
2927
import org.labkey.api.util.ResultSetUtil;
30-
import org.springframework.beans.MutablePropertyValues;
31-
import org.springframework.beans.PropertyValues;
32-
import org.springframework.validation.BindException;
33-
import org.springframework.validation.ObjectError;
3428

3529
import java.lang.reflect.Constructor;
3630
import java.lang.reflect.Field;
@@ -190,154 +184,17 @@ public void testDatabase() throws SQLException
190184
rs.next();
191185
Assert.assertEquals(users.getFirst(), factory.handle(rs));
192186
}
193-
MiniUser randomUser = users.get((int)(Math.random() * users.size()));
187+
MiniUser randomUser = users.get((int) (Math.random() * users.size()));
194188
MiniUser selectedUser = new TableSelector(CoreSchema.getInstance().getTableInfoUsers(), new SimpleFilter(FieldKey.fromString("UserId"), randomUser.UserId), null).getObject(MiniUser.class);
195189
Assert.assertEquals(randomUser, selectedUser);
196190

197191
// Test fromMap() variant (should ignore selectedUser)
198192
assertEquals(adHocUser, factory.fromMap(selectedUser, adHocMap));
199193
}
194+
}
200195

201-
@Test
202-
public void testBinding()
203-
{
204-
Date lastLogin = new Date();
205-
206-
// Provide all parameters
207-
Map<String, Object> params = Map.of(
208-
"firstName", "Fred",
209-
"lastName", "Flintstone",
210-
"lastLogin", DateUtil.formatIsoDateLongTime(lastLogin),
211-
"userId", 1009
212-
);
213-
String toString = "MiniUser[FIRSTname=Fred, LASTNAME=Flintstone, lastLogin=" + lastLogin + ", UserId=1009]";
214-
testRecordBinding(params, toString);
215-
testFormBinding(params, toString);
216-
217-
// Provide just the primitive parameter; others are nullable
218-
params = Map.of(
219-
"userId", 1009
220-
);
221-
toString = "MiniUser[FIRSTname=null, LASTNAME=null, lastLogin=null, UserId=1009]";
222-
testRecordBinding(params, toString);
223-
testFormBinding(params, toString);
224-
225-
// No parameters should fail for record due to "userid" primitive. Ensure a reasonable error message.
226-
testRecordBinding(Map.of(), "Primitive parameter \"UserId\" is required");
227-
// No parameters should succeed for form class. UserId simply defaults to 0;
228-
testFormBinding(Map.of(), "MiniUser[FIRSTname=null, LASTNAME=null, lastLogin=null, UserId=0]");
229-
230-
// Verify message for conversion error
231-
params = Map.of("UserId", "abc");
232-
String errorMessage = "Failed to convert property value of type 'java.lang.String' to required type 'int' for property 'UserId'; Could not convert 'abc' to an integer";
233-
testRecordBinding(params, errorMessage);
234-
testFormBinding(params, errorMessage);
235-
}
236-
237-
private void testRecordBinding(Map<String, Object> map, String expectedToStringOrError)
238-
{
239-
PropertyValues pvs = new MutablePropertyValues(map);
240-
BindException be = BaseViewAction.bindParametersToRecord(MiniUser.class, pvs, "form");
241-
242-
if (be.hasErrors())
243-
{
244-
validateError(be, expectedToStringOrError);
245-
}
246-
else
247-
{
248-
validateTarget(be.getTarget(), expectedToStringOrError);
249-
}
250-
}
251-
252-
private void testFormBinding(Map<String, Object> map, String expectedToStringOrError)
253-
{
254-
PropertyValues pvs = new MutablePropertyValues(map);
255-
BindException be = BaseViewAction.defaultBindParameters(new MiniUserForm(), "form", pvs);
256-
257-
if (be.hasErrors())
258-
{
259-
validateError(be, expectedToStringOrError);
260-
}
261-
else
262-
{
263-
validateTarget(be.getTarget(), expectedToStringOrError);
264-
}
265-
}
266-
267-
private void validateError(BindException be, String expectedErrorMessage)
268-
{
269-
ObjectError error = be.getAllErrors().getFirst();
270-
assertNotNull(error);
271-
assertEquals(expectedErrorMessage, error.getDefaultMessage());
272-
}
273-
274-
private void validateTarget(Object user, String expectedToString)
275-
{
276-
assertNotNull(user);
277-
assertEquals(expectedToString, user.toString());
278-
}
279-
280-
// Simple test record. Weird casing is intentional to test case-insensitivity.
281-
private record MiniUser(String FIRSTname, String LASTNAME, Date lastLogin, int UserId)
282-
{
283-
}
284-
285-
// Simple test form
286-
@SuppressWarnings("unused")
287-
private static class MiniUserForm
288-
{
289-
String _firstName;
290-
String _lastName;
291-
Date _lastLogin;
292-
int _userId;
293-
294-
public String getFirstName()
295-
{
296-
return _firstName;
297-
}
298-
299-
public void setFirstName(String firstName)
300-
{
301-
_firstName = firstName;
302-
}
303-
304-
public String getLastName()
305-
{
306-
return _lastName;
307-
}
308-
309-
public void setLastName(String lastName)
310-
{
311-
_lastName = lastName;
312-
}
313-
314-
public Date getLastLogin()
315-
{
316-
return _lastLogin;
317-
}
318-
319-
public void setLastLogin(Date lastLogin)
320-
{
321-
_lastLogin = lastLogin;
322-
}
323-
324-
public int getUserId()
325-
{
326-
return _userId;
327-
}
328-
329-
public void setUserId(int userId)
330-
{
331-
_userId = userId;
332-
}
333-
334-
@Override
335-
public String toString()
336-
{
337-
// No useful default toString(), so emulate the standard record toString(). That's good enough to verify
338-
// that the parameters were bound correctly.
339-
return "MiniUser[FIRSTname=" + _firstName + ", LASTNAME=" + _lastName + ", lastLogin=" + _lastLogin + ", UserId=" + _userId + "]";
340-
}
341-
}
196+
// Simple test record. Weird casing is intentional to test case-insensitivity.
197+
record MiniUser(String FIRSTname, String LASTNAME, Date lastLogin, int UserId)
198+
{
342199
}
343200
}

0 commit comments

Comments
 (0)