This is an automated email from the ASF dual-hosted git repository.
jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git
The following commit(s) were added to refs/heads/master by this push:
new 98f88e3f7 Test modernization
98f88e3f7 is described below
commit 98f88e3f7bebbf43620b8a805b9f6ac7e4404739
Author: James Bognar <[email protected]>
AuthorDate: Sat Aug 30 11:36:13 2025 -0400
Test modernization
---
.../src/test/java/org/apache/juneau/TestUtils.java | 90 ++++++++++++++++++++--
.../http/annotation/ContentAnnotation_Test.java | 9 +--
2 files changed, 84 insertions(+), 15 deletions(-)
diff --git a/juneau-utest/src/test/java/org/apache/juneau/TestUtils.java
b/juneau-utest/src/test/java/org/apache/juneau/TestUtils.java
index 9d92901c2..742bfa128 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/TestUtils.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/TestUtils.java
@@ -143,7 +143,8 @@ public class TestUtils extends Utils2 {
* Asserts that the fields/properties on the specified bean are the
specified values after being converted to {@link Utils#r readable} strings.
*
* <p>This is the primary method for Bean-Centric Test Modernization
(BCTM), supporting extensive property validation
- * patterns including nested objects, collections, arrays, method
chaining, and direct field access.</p>
+ * patterns including nested objects, collections, arrays, method
chaining, direct field access, collection iteration
+ * with <js>#{property}</js> syntax, and universal
<js>length</js>/<js>size</js> properties for all collection types.</p>
*
* <h5 class='section'>Basic Usage:</h5>
* <p class='bjava'>
@@ -175,6 +176,35 @@ public class TestUtils extends Utils2 {
* assertBean(myBean, <js>"items{length}"</js>, <js>"{5}"</js>);
* </p>
*
+ * <h5 class='section'>Collection Iteration Syntax:</h5>
+ * <p class='bjava'>
+ * <jc>// Test properties across ALL elements in a collection
using #{...} syntax</jc>
+ * assertBean(myBean, <js>"userList{#{name}}"</js>,
<js>"[{John},{Jane},{Bob}]"</js>);
+ *
+ * <jc>// Test multiple properties from each element</jc>
+ * assertBean(myBean, <js>"orderList{#{id,status}}"</js>,
<js>"[{123,ACTIVE},{124,PENDING}]"</js>);
+ *
+ * <jc>// Works with nested properties within each element</jc>
+ * assertBean(myBean, <js>"customers{#{address{city}}}"</js>,
<js>"[{{New York}},{{Los Angeles}}]"</js>);
+ *
+ * <jc>// Works with arrays and any iterable collection type</jc>
+ * assertBean(config, <js>"itemArray{#{type}}"</js>,
<js>"[{String},{Integer},{Boolean}]"</js>);
+ * assertBean(data, <js>"statusSet{#{name}}"</js>,
<js>"[{ACTIVE},{PENDING},{CANCELLED}]"</js>);
+ * </p>
+ *
+ * <h5 class='section'>Universal Collection Size Properties:</h5>
+ * <p class='bjava'>
+ * <jc>// Both 'length' and 'size' work universally across all
collection types</jc>
+ * assertBean(myBean, <js>"myArray{length}"</js>, <js>"{5}"</js>);
<jc>// Arrays</jc>
+ * assertBean(myBean, <js>"myArray{size}"</js>, <js>"{5}"</js>);
<jc>// Also works for arrays</jc>
+ *
+ * assertBean(myBean, <js>"myList{size}"</js>, <js>"{3}"</js>);
<jc>// Collections</jc>
+ * assertBean(myBean, <js>"myList{length}"</js>, <js>"{3}"</js>);
<jc>// Also works for collections</jc>
+ *
+ * assertBean(myBean, <js>"myMap{size}"</js>, <js>"{7}"</js>);
<jc>// Maps</jc>
+ * assertBean(myBean, <js>"myMap{length}"</js>, <js>"{7}"</js>);
<jc>// Also works for maps</jc>
+ * </p>
+ *
* <h5 class='section'>Class Name Testing:</h5>
* <p class='bjava'>
* <jc>// Test class properties (prefer simple names for
maintainability)</jc>
@@ -194,6 +224,24 @@ public class TestUtils extends Utils2 {
* );
* </p>
*
+ * <h5 class='section'>Advanced Collection Analysis:</h5>
+ * <p class='bjava'>
+ * <jc>// Combine size/length, metadata, and content iteration in
single assertions</jc>
+ * assertBean(myBean,
<js>"users{length,class{simpleName},#{name}}"</js>,
+ * <js>"{3,{ArrayList},[{John},{Jane},{Bob}]}"</js>);
+ *
+ * <jc>// Comprehensive collection validation with multiple
iteration patterns</jc>
+ * assertBean(order, <js>"items{size,#{name},#{price}}"</js>,
+ *
<js>"{3,[{Laptop},{Phone},{Tablet}],[{999.99},{599.99},{399.99}]}"</js>);
+ *
+ * <jc>// Perfect for validation testing - verify error count and
details</jc>
+ * assertBean(result, <js>"errors{length,#{field},#{code}}"</js>,
+ * <js>"{2,[{email},{password}],[{E001},{E002}]}"</js>);
+ *
+ * <jc>// Mixed collection types with consistent syntax</jc>
+ * assertBean(response, <js>"results{size},metadata{length}"</js>,
<js>"{25},{4}"</js>);
+ * </p>
+ *
* <h5 class='section'>Direct Field Access:</h5>
* <p class='bjava'>
* <jc>// Test public fields directly (no getters required)</jc>
@@ -218,17 +266,19 @@ public class TestUtils extends Utils2 {
* <li><b>Nested values:</b> <js>"{value}"</js> for single-level
nested properties</li>
* <li><b>Deep nested values:</b> <js>"{{value}}"</js>,
<js>"{{{value}}}"</js> for multiple nesting levels</li>
* <li><b>Array/Collection values:</b> <js>"[item1,item2]"</js>
for collections</li>
+ * <li><b>Collection iteration:</b> <js>"#{property}"</js>
iterates over ALL collection elements, returns <js>"[{val1},{val2}]"</js></li>
+ * <li><b>Universal size properties:</b> <js>"length"</js> and
<js>"size"</js> work on arrays, collections, and maps</li>
* <li><b>Boolean values:</b> <js>"true"</js>,
<js>"false"</js></li>
* <li><b>Null values:</b> <js>"null"</js></li>
* </ul>
*
* <h5 class='section'>Property Access Priority:</h5>
* <ol>
+ * <li><b>Universal size properties:</b> <js>"length"</js> and
<js>"size"</js> for arrays, collections, and maps</li>
* <li><b>is{Property}()</b> methods (for boolean properties)</li>
* <li><b>get{Property}()</b> methods</li>
* <li><b>Public fields</b> (direct field access)</li>
* <li><b>get(String)</b> methods (for Map-like objects)</li>
- * <li><b>Special array properties:</b> <js>"length"</js> for
arrays</li>
* </ol>
*
* @param bean The bean object to test. Must not be null.
@@ -975,11 +1025,14 @@ public class TestUtils extends Utils2 {
m.setAccessible(true);
return m.invoke(o, name);
}
- if (c.isArray()) {
- switch (name) {
- case "length": return
Array.getLength(o);
- default: // Fall through.
- }
+ if ("length".equals(name) && c.isArray()) {
+ return Array.getLength(o);
+ }
+ if ("size".equals(name)) {
+ if (isConvertibleToList(o))
+ return convertToList(o).size();
+ else if (o instanceof Map o2)
+ return o2.size();
}
throw runtimeException("No field called {0} found on
class {1}", name, c.getName());
});
@@ -990,6 +1043,14 @@ public class TestUtils extends Utils2 {
}
private static String getEntry(Object o, String name) {
+
+ // Handle #{...} syntax for iterating over collections/arrays
+ if (name.startsWith("#{") && name.endsWith("}") &&
isConvertibleToList(o)) {
+ var spn = splitNestedInner(name);
+ return convertToList(o).stream().map(x ->
spn.stream().map(x2 -> getEntry(x,
x2)).collect(joining(",","{","}"))).collect(joining(",","[","]"));
+ }
+
+ // Original logic for regular property access
var i = name.indexOf("{");
var pn = i == -1 ? name : name.substring(0, i);
var spn = i == -1 ? null : splitNestedInner(name);
@@ -1009,6 +1070,21 @@ public class TestUtils extends Utils2 {
return getBeanProp(o, name);
}
+ private static boolean isConvertibleToList(Object o) {
+ return o != null && (o instanceof Collection || o instanceof
Iterable || o instanceof Iterator || o instanceof Enumeration ||
o.getClass().isArray());
+ }
+
+ @SuppressWarnings("unchecked")
+ private static List<?> convertToList(Object o) {
+ assertArgNotNull("o", o);
+ if (o instanceof List o2) return o2;
+ if (o instanceof Iterable o2) return toList(o2);
+ if (o instanceof Iterator o2) return toList(o2);
+ if (o instanceof Enumeration o2) return toList(o2);
+ if (o.getClass().isArray()) return arrayToList(o);
+ throw runtimeException("Could not convert object of type {0} to
a list", o.getClass().getName());
+ }
+
/**
* Gets the swagger for the specified @Resource-annotated object.
* @param c
diff --git
a/juneau-utest/src/test/java/org/apache/juneau/http/annotation/ContentAnnotation_Test.java
b/juneau-utest/src/test/java/org/apache/juneau/http/annotation/ContentAnnotation_Test.java
index c71598ab5..d3d6bc5de 100644
---
a/juneau-utest/src/test/java/org/apache/juneau/http/annotation/ContentAnnotation_Test.java
+++
b/juneau-utest/src/test/java/org/apache/juneau/http/annotation/ContentAnnotation_Test.java
@@ -41,14 +41,7 @@ class ContentAnnotation_Test extends SimpleTestBase {
.build();
@Test void a01_basic() {
- assertJsonMatches(a1, ""
- + "{"
- + "description:['description'],"
- + "on:['on'],"
- + "onClass:['"+CNAME+"$X1'],"
- + "schema:{*}"
- + "}"
- );
+ assertBean(a1,
"description,on,onClass{length,#{simpleName}},schema{description}",
"[description],[on],{1,[{X1}]},{[]}");
}
@Test void a02_testEquivalency() {