Skip to content

Commit 01a8c28

Browse files
committed
Add comprehensive edge case tests for record support
1 parent 42928d9 commit 01a8c28

File tree

2 files changed

+160
-20
lines changed

2 files changed

+160
-20
lines changed
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
package org.json.junit;
2+
3+
import static org.junit.Assert.assertEquals;
4+
import static org.junit.Assert.assertFalse;
5+
import static org.junit.Assert.assertTrue;
6+
7+
import java.io.StringReader;
8+
9+
import org.json.JSONObject;
10+
import org.json.junit.data.GenericBeanInt;
11+
import org.json.junit.data.MyEnum;
12+
import org.json.junit.data.MyNumber;
13+
import org.json.junit.data.PersonRecord;
14+
import org.junit.Test;
15+
16+
/**
17+
* Tests for JSONObject support of Java record-style classes.
18+
* These tests verify that classes with accessor methods without get/is prefixes
19+
* (like Java records) can be properly converted to JSONObject.
20+
*/
21+
public class JSONObjectRecordTest {
22+
23+
/**
24+
* Tests that JSONObject can be created from a record-style class.
25+
* Record-style classes use accessor methods like name() instead of getName().
26+
*/
27+
@Test
28+
public void jsonObjectByRecord() {
29+
PersonRecord person = new PersonRecord("John Doe", 30, true);
30+
JSONObject jsonObject = new JSONObject(person);
31+
32+
assertEquals("Expected 3 keys in the JSONObject", 3, jsonObject.length());
33+
assertEquals("John Doe", jsonObject.get("name"));
34+
assertEquals(30, jsonObject.get("age"));
35+
assertEquals(true, jsonObject.get("active"));
36+
}
37+
38+
/**
39+
* Test that Object methods (toString, hashCode, equals, etc.) are not included
40+
*/
41+
@Test
42+
public void recordStyleClassShouldNotIncludeObjectMethods() {
43+
PersonRecord person = new PersonRecord("Jane Doe", 25, false);
44+
JSONObject jsonObject = new JSONObject(person);
45+
46+
// Should NOT include Object methods
47+
assertFalse("Should not include toString", jsonObject.has("toString"));
48+
assertFalse("Should not include hashCode", jsonObject.has("hashCode"));
49+
assertFalse("Should not include equals", jsonObject.has("equals"));
50+
assertFalse("Should not include clone", jsonObject.has("clone"));
51+
assertFalse("Should not include wait", jsonObject.has("wait"));
52+
assertFalse("Should not include notify", jsonObject.has("notify"));
53+
assertFalse("Should not include notifyAll", jsonObject.has("notifyAll"));
54+
55+
// Should only have the 3 record fields
56+
assertEquals("Should only have 3 fields", 3, jsonObject.length());
57+
}
58+
59+
/**
60+
* Test that enum methods are not included when processing an enum
61+
*/
62+
@Test
63+
public void enumsShouldNotIncludeEnumMethods() {
64+
MyEnum myEnum = MyEnum.VAL1;
65+
JSONObject jsonObject = new JSONObject(myEnum);
66+
67+
// Should NOT include enum-specific methods like name(), ordinal(), values(), valueOf()
68+
assertFalse("Should not include name method", jsonObject.has("name"));
69+
assertFalse("Should not include ordinal method", jsonObject.has("ordinal"));
70+
assertFalse("Should not include declaringClass", jsonObject.has("declaringClass"));
71+
72+
// Enums should still work with traditional getters if they have any
73+
// But should not pick up the built-in enum methods
74+
}
75+
76+
/**
77+
* Test that Number subclass methods are not included
78+
*/
79+
@Test
80+
public void numberSubclassesShouldNotIncludeNumberMethods() {
81+
MyNumber myNumber = new MyNumber();
82+
JSONObject jsonObject = new JSONObject(myNumber);
83+
84+
// Should NOT include Number methods like intValue(), longValue(), etc.
85+
assertFalse("Should not include intValue", jsonObject.has("intValue"));
86+
assertFalse("Should not include longValue", jsonObject.has("longValue"));
87+
assertFalse("Should not include doubleValue", jsonObject.has("doubleValue"));
88+
assertFalse("Should not include floatValue", jsonObject.has("floatValue"));
89+
90+
// Should include the actual getter
91+
assertTrue("Should include number", jsonObject.has("number"));
92+
assertEquals("Should have 1 field", 1, jsonObject.length());
93+
}
94+
95+
/**
96+
* Test that generic bean with get() and is() methods works correctly
97+
*/
98+
@Test
99+
public void genericBeanWithGetAndIsMethodsShouldNotBeIncluded() {
100+
GenericBeanInt bean = new GenericBeanInt(42);
101+
JSONObject jsonObject = new JSONObject(bean);
102+
103+
// Should NOT include standalone get() or is() methods
104+
assertFalse("Should not include standalone 'get' method", jsonObject.has("get"));
105+
assertFalse("Should not include standalone 'is' method", jsonObject.has("is"));
106+
107+
// Should include the actual getters
108+
assertTrue("Should include genericValue field", jsonObject.has("genericValue"));
109+
assertTrue("Should include a field", jsonObject.has("a"));
110+
}
111+
112+
/**
113+
* Test that java.* classes don't have their methods picked up
114+
*/
115+
@Test
116+
public void javaLibraryClassesShouldNotIncludeTheirMethods() {
117+
StringReader reader = new StringReader("test");
118+
JSONObject jsonObject = new JSONObject(reader);
119+
120+
// Should NOT include java.io.Reader methods like read(), reset(), etc.
121+
assertFalse("Should not include read method", jsonObject.has("read"));
122+
assertFalse("Should not include reset method", jsonObject.has("reset"));
123+
assertFalse("Should not include ready method", jsonObject.has("ready"));
124+
assertFalse("Should not include skip method", jsonObject.has("skip"));
125+
126+
// Reader should produce empty JSONObject (no valid properties)
127+
assertEquals("Reader should produce empty JSON", 0, jsonObject.length());
128+
}
129+
130+
/**
131+
* Test mixed case - object with both traditional getters and record-style accessors
132+
*/
133+
@Test
134+
public void mixedGettersAndRecordStyleAccessors() {
135+
// PersonRecord has record-style accessors: name(), age(), active()
136+
// These should all be included
137+
PersonRecord person = new PersonRecord("Mixed Test", 40, true);
138+
JSONObject jsonObject = new JSONObject(person);
139+
140+
assertEquals("Should have all 3 record-style fields", 3, jsonObject.length());
141+
assertTrue("Should include name", jsonObject.has("name"));
142+
assertTrue("Should include age", jsonObject.has("age"));
143+
assertTrue("Should include active", jsonObject.has("active"));
144+
}
145+
146+
/**
147+
* Test that methods starting with uppercase are not included (not valid record accessors)
148+
*/
149+
@Test
150+
public void methodsStartingWithUppercaseShouldNotBeIncluded() {
151+
PersonRecord person = new PersonRecord("Test", 50, false);
152+
JSONObject jsonObject = new JSONObject(person);
153+
154+
// Record-style accessors must start with lowercase
155+
// Methods like Name(), Age() (uppercase) should not be picked up
156+
// Our PersonRecord only has lowercase accessors, which is correct
157+
158+
assertEquals("Should only have lowercase accessors", 3, jsonObject.length());
159+
}
160+
}

src/test/java/org/json/junit/JSONObjectTest.java

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@
5151
import org.json.junit.data.MyNumber;
5252
import org.json.junit.data.MyNumberContainer;
5353
import org.json.junit.data.MyPublicClass;
54-
import org.json.junit.data.PersonRecord;
5554
import org.json.junit.data.RecursiveBean;
5655
import org.json.junit.data.RecursiveBeanEquals;
5756
import org.json.junit.data.Singleton;
@@ -786,25 +785,6 @@ public void jsonObjectByBean3() {
786785
Util.checkJSONObjectMaps(jsonObject);
787786
}
788787

789-
/**
790-
* JSONObject built from a Java record.
791-
* Records use accessor methods without get/is prefixes (e.g., name() instead of getName()).
792-
* This test verifies that JSONObject correctly handles record types.
793-
*/
794-
@Test
795-
public void jsonObjectByRecord() {
796-
PersonRecord person = new PersonRecord("John Doe", 30, true);
797-
JSONObject jsonObject = new JSONObject(person);
798-
799-
// validate JSON
800-
Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString());
801-
assertTrue("expected 3 top level items", ((Map<?,?>)(JsonPath.read(doc, "$"))).size() == 3);
802-
assertTrue("expected name field", "John Doe".equals(jsonObject.query("/name")));
803-
assertTrue("expected age field", Integer.valueOf(30).equals(jsonObject.query("/age")));
804-
assertTrue("expected active field", Boolean.TRUE.equals(jsonObject.query("/active")));
805-
Util.checkJSONObjectMaps(jsonObject);
806-
}
807-
808788
/**
809789
* A bean is also an object. But in order to test the JSONObject
810790
* ctor that takes an object and a list of names,

0 commit comments

Comments
 (0)