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 447aadfea Test modernization
447aadfea is described below

commit 447aadfea6babed0c08cc4c78bd2d61e390ca7b6
Author: James Bognar <[email protected]>
AuthorDate: Thu Sep 11 10:05:18 2025 -0400

    Test modernization
---
 .../apache/juneau/junit/AssertionArgs_Test.java    |   2 +-
 .../java/org/apache/juneau/junit/Assertions2.java  | 158 ++++----
 .../apache/juneau/junit/BasicBeanConverter.java    |  37 +-
 .../juneau/junit/BasicBeanConverter_Test.java      | 431 +++++++++++++++++++++
 .../org/apache/juneau/junit/NestedTokenizer.java   |   2 +-
 .../apache/juneau/junit/NestedTokenizer_Test.java  |   2 +-
 .../apache/juneau/junit/PropertyExtractors.java    |  15 +-
 .../juneau/junit/PropertyExtractors_Test.java      | 359 +++++++++++++++++
 .../java/org/apache/juneau/junit/TestBase.java     |  26 ++
 .../test/java/org/apache/juneau/junit/Utils.java   |  10 +-
 .../java/org/apache/juneau/junit/Utils_Test.java   |  58 ++-
 11 files changed, 961 insertions(+), 139 deletions(-)

diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/junit/AssertionArgs_Test.java 
b/juneau-utest/src/test/java/org/apache/juneau/junit/AssertionArgs_Test.java
index 033c5a8d9..68a011aa7 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/junit/AssertionArgs_Test.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/junit/AssertionArgs_Test.java
@@ -28,7 +28,7 @@ import org.junit.jupiter.api.*;
  * <p>Tests the configuration and behavior of the assertion arguments class 
including
  * bean converter customization, error message composition, and fluent API 
functionality.</p>
  */
-class AssertionArgs_Test {
+class AssertionArgs_Test extends TestBase {
 
        // Test objects for assertions
        static class TestBean {
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/junit/Assertions2.java 
b/juneau-utest/src/test/java/org/apache/juneau/junit/Assertions2.java
index 095537347..72e8ea97f 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/junit/Assertions2.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/junit/Assertions2.java
@@ -78,19 +78,19 @@ import org.opentest4j.*;
  * <p><b>Basic Property Testing:</b></p>
  * <p class='bjava'>
  *     <jc>// Test multiple properties</jc>
- *     <jsm>assertBean</jsm>(user, <js>"name,age,active"</js>, 
<js>"John,30,true"</js>);
+ *     <jsm>assertBean</jsm>(<jv>user</jv>, <js>"name,age,active"</js>, 
<js>"John,30,true"</js>);
  *
- *     <jc>// Test nested properties</jc>
- *     <jsm>assertBean</jsm>(user, <js>"name,address{street,city}"</js>, 
<js>"John,{123 Main St,Springfield}"</js>);
+ *     <jc>// Test nested properties - user has getAddress() returning Address 
with getStreet() and getCity()</jc>
+ *     <jsm>assertBean</jsm>(<jv>user</jv>, 
<js>"name,address{street,city}"</js>, <js>"John,{123 Main 
St,Springfield}"</js>);
  * </p>
  *
  * <p><b>Collection and Array Testing:</b></p>
  * <p class='bjava'>
- *     <jc>// Test collection size and iterate over all elements</jc>
- *     <jsm>assertBean</jsm>(order, <js>"items{length,#{name}}"</js>, 
<js>"{3,[{Laptop},{Phone},{Tablet}]}"</js>);
+ *     <jc>// Test collection size and iterate over all elements - order has 
getItems() returning List&lt;Product&gt; where Product has getName()</jc>
+ *     <jsm>assertBean</jsm>(<jv>order</jv>, <js>"items{length,#{name}}"</js>, 
<js>"{3,[{Laptop},{Phone},{Tablet}]}"</js>);
  *
- *     <jc>// Test specific array elements</jc>
- *     <jsm>assertBean</jsm>(listOfData, <js>"0{data},1{data}"</js>, 
<js>"{100},{200}"</js>);
+ *     <jc>// Test specific array elements - listOfData is a 
List&lt;DataObject&gt; where DataObject has getData()</jc>
+ *     <jsm>assertBean</jsm>(<jv>listOfData</jv>, <js>"0{data},1{data}"</js>, 
<js>"{100},{200}"</js>);
  * </p>
  *
  * <p><b>Collection Testing:</b></p>
@@ -99,7 +99,7 @@ import org.opentest4j.*;
  *     <jsm>assertList</jsm>(tags, <js>"red"</js>, <js>"green"</js>, 
<js>"blue"</js>);
  *
  *     <jc>// Test map entries using assertBean</jc>
- *     <jsm>assertBean</jsm>(config, <js>"timeout,retries"</js>, 
<js>"30000,3"</js>);
+ *     <jsm>assertBean</jsm>(<jv>config</jv>, <js>"timeout,retries"</js>, 
<js>"30000,3"</js>);
  * </p>
  *
  * <p><b>Custom Property Access:</b></p>
@@ -187,71 +187,71 @@ public class Assertions2 {
         * <h5 class='section'>Nested Property Testing:</h5>
         * <p class='bjava'>
         *      <jc>// Test nested bean properties</jc>
-        *      <jsm>assertBean</jsm>(<jv>myBean</jv>, 
<js>"address{street,city,state}"</js>, <js>"{123 Main St,Springfield,IL}"</js>);
+        *      <jsm>assertBean</jsm>(<jv>myBean</jv>, 
<js>"name,address{street,city,state}"</js>, <js>"John,{123 Main 
St,Springfield,IL}"</js>);
         *
         *      <jc>// Test arbitrarily deep nesting</jc>
-        *      <jsm>assertBean</jsm>(<jv>myBean</jv>, 
<js>"person{address{geo{lat,lon}}}"</js>, <js>"{{{{40.7,-74.0}}}}"</js>);
+        *      <jsm>assertBean</jsm>(<jv>myBean</jv>, 
<js>"name,person{address{geo{lat,lon}}}"</js>, 
<js>"John,{{{40.7,-74.0}}}"</js>);
         * </p>
         *
          * <h5 class='section'>Array, List, and Stream Testing:</h5>
         * <p class='bjava'>
-        *      <jc>// Test array/list elements by index</jc>
-        *      assertBean(myBean, <js>"items{0,1,2}"</js>, 
<js>"{item1,item2,item3}"</js>);
+        *      <jc>// Test array/list elements by index - items is a String[] 
or List&lt;String&gt;</jc>
+        *      <jsm>assertBean</jsm>(<jv>myBean</jv>, <js>"items{0,1,2}"</js>, 
<js>"{item1,item2,item3}"</js>);
         *
-        *      <jc>// Test nested properties within array elements</jc>
-        *      assertBean(myBean, <js>"orders{0{id,total}}"</js>, 
<js>"{{123,99.95}}"</js>);
+        *      <jc>// Test nested properties within array elements - orders is 
a List&lt;Order&gt; where Order has getId() and getTotal()</jc>
+        *      <jsm>assertBean</jsm>(<jv>myBean</jv>, 
<js>"orders{0{id,total}}"</js>, <js>"{{123,99.95}}"</js>);
         *
-        *      <jc>// Test array length property</jc>
-        *      assertBean(myBean, <js>"items{length}"</js>, <js>"{5}"</js>);
+        *      <jc>// Test array length property - items can be any array or 
collection type</jc>
+        *      <jsm>assertBean</jsm>(<jv>myBean</jv>, 
<js>"items{length}"</js>, <js>"{5}"</js>);
         *
-        *      <jc>// Works with any iterable type including Streams</jc>
-        *      assertBean(myBean, <js>"userStream{#{name}}"</js>, 
<js>"[{Alice},{Bob}]"</js>);
+        *      <jc>// Works with any iterable type including Streams - 
userStream returns a Stream&lt;User&gt; where User has getName()</jc>
+        *      <jsm>assertBean</jsm>(<jv>myBean</jv>, 
<js>"userStream{#{name}}"</js>, <js>"[{Alice},{Bob}]"</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 properties across ALL elements in a collection 
using #{...} syntax - userList is a List&lt;User&gt; where User has 
getName()</jc>
+        *      <jsm>assertBean</jsm>(<jv>myBean</jv>, 
<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>// Test multiple properties from each element - orderList 
is a List&lt;Order&gt; where Order has getId() and getStatus()</jc>
+        *      <jsm>assertBean</jsm>(<jv>myBean</jv>, 
<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 nested properties within each element - 
customers is a List&lt;Customer&gt; where Customer has getAddress() returning 
Address with getCity()</jc>
+        *      <jsm>assertBean</jsm>(<jv>myBean</jv>, 
<js>"customers{#{address{city}}}"</js>, <js>"[{{New York}},{{Los 
Angeles}}]"</js>);
         *
          *     <jc>// Works with arrays and any iterable collection type 
(including Streams)</jc>
-        *      assertBean(config, <js>"itemArray{#{type}}"</js>, 
<js>"[{String},{Integer},{Boolean}]"</js>);
-        *      assertBean(data, <js>"statusSet{#{name}}"</js>, 
<js>"[{ACTIVE},{PENDING},{CANCELLED}]"</js>);
-        *      assertBean(processor, <js>"dataStream{#{value}}"</js>, 
<js>"[{A},{B},{C}]"</js>);
+        *      <jsm>assertBean</jsm>(<jv>config</jv>, 
<js>"itemArray{#{type}}"</js>, <js>"[{String},{Integer},{Boolean}]"</js>);
+        *      <jsm>assertBean</jsm>(<jv>data</jv>, 
<js>"statusSet{#{name}}"</js>, <js>"[{ACTIVE},{PENDING},{CANCELLED}]"</js>);
+        *      <jsm>assertBean</jsm>(<jv>processor</jv>, 
<js>"dataStream{#{value}}"</js>, <js>"[{A},{B},{C}]"</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>
+        *      <jsm>assertBean</jsm>(<jv>myBean</jv>, 
<js>"myArray{length}"</js>, <js>"{5}"</js>);        <jc>// Arrays</jc>
+        *      <jsm>assertBean</jsm>(<jv>myBean</jv>, 
<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>
+        *      <jsm>assertBean</jsm>(<jv>myBean</jv>, <js>"myList{size}"</js>, 
<js>"{3}"</js>);           <jc>// Collections</jc>
+        *      <jsm>assertBean</jsm>(<jv>myBean</jv>, 
<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>
+        *      <jsm>assertBean</jsm>(<jv>myBean</jv>, <js>"myMap{size}"</js>, 
<js>"{7}"</js>);            <jc>// Maps</jc>
+        *      <jsm>assertBean</jsm>(<jv>myBean</jv>, 
<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>
-        *      assertBean(myBean, <js>"obj{class{simpleName}}"</js>, 
<js>"{{MyClass}}"</js>);
+        *      <jsm>assertBean</jsm>(<jv>myBean</jv>, 
<js>"obj{class{simpleName}}"</js>, <js>"{{MyClass}}"</js>);
         *
         *      <jc>// Test full class names when needed</jc>
-        *      assertBean(myBean, <js>"obj{class{name}}"</js>, 
<js>"{{com.example.MyClass}}"</js>);
+        *      <jsm>assertBean</jsm>(<jv>myBean</jv>, 
<js>"obj{class{name}}"</js>, <js>"{{com.example.MyClass}}"</js>);
         * </p>
         *
         * <h5 class='section'>Method Chaining Support:</h5>
         * <p class='bjava'>
         *      <jc>// Test fluent setter chains (returns same object)</jc>
-        *      assertBean(
-        *              
item.setType(<js>"foo"</js>).setFormat(<js>"bar"</js>).setDefault(<js>"baz"</js>),
+        *      <jsm>assertBean</jsm>(
+        *              
<jv>item</jv>.setType(<js>"foo"</js>).setFormat(<js>"bar"</js>).setDefault(<js>"baz"</js>),
         *              <js>"type,format,default"</js>,
         *              <js>"foo,bar,baz"</js>
         *      );
@@ -259,50 +259,50 @@ public class Assertions2 {
         *
         * <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>,
+        *      <jc>// Combine size/length, metadata, and content iteration in 
single assertions - users is a List&lt;User&gt;</jc>
+        *      <jsm>assertBean</jsm>(<jv>myBean</jv>, 
<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>,
+        *      <jc>// Comprehensive collection validation with multiple 
iteration patterns - items is a List&lt;Product&gt; where Product has getName() 
and getPrice()</jc>
+        *      <jsm>assertBean</jsm>(<jv>order</jv>, 
<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>,
+        *      <jc>// Perfect for validation testing - verify error count and 
details; errors is a List&lt;ValidationError&gt; where ValidationError has 
getField() and getCode()</jc>
+        *      <jsm>assertBean</jsm>(<jv>result</jv>, 
<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>);
+        *      <jc>// Mixed collection types with consistent syntax - results 
and metadata are different collection types</jc>
+        *      <jsm>assertBean</jsm>(<jv>response</jv>, 
<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>
-        *      assertBean(myBean, <js>"f1,f2,f3"</js>, 
<js>"val1,val2,val3"</js>);
+        *      <jsm>assertBean</jsm>(<jv>myBean</jv>, <js>"f1,f2,f3"</js>, 
<js>"val1,val2,val3"</js>);
         *
         *      <jc>// Test field properties with chaining</jc>
-        *      assertBean(myBean, <js>"f1{length},f2{class{simpleName}}"</js>, 
<js>"{5},{{String}}"</js>);
+        *      <jsm>assertBean</jsm>(<jv>myBean</jv>, 
<js>"f1{length},f2{class{simpleName}}"</js>, <js>"{5},{{String}}"</js>);
         * </p>
         *
          * <h5 class='section'>Map Testing:</h5>
         * <p class='bjava'>
         *      <jc>// Test map values by key</jc>
-        *      assertBean(myBean, <js>"configMap{timeout,retries}"</js>, 
<js>"{30000,3}"</js>);
+        *      <jsm>assertBean</jsm>(<jv>myBean</jv>, 
<js>"configMap{timeout,retries}"</js>, <js>"{30000,3}"</js>);
         *
         *      <jc>// Test map size</jc>
-        *      assertBean(myBean, <js>"settings{size}"</js>, <js>"{5}"</js>);
+        *      <jsm>assertBean</jsm>(<jv>myBean</jv>, 
<js>"settings{size}"</js>, <js>"{5}"</js>);
         *
         *      <jc>// Test null keys using special &lt;NULL&gt; syntax</jc>
-        *      assertBean(myBean, <js>"mapWithNullKey{&lt;NULL&gt;}"</js>, 
<js>"{nullKeyValue}"</js>);
+        *      <jsm>assertBean</jsm>(<jv>myBean</jv>, 
<js>"mapWithNullKey{&lt;NULL&gt;}"</js>, <js>"{nullKeyValue}"</js>);
         * </p>
         *
         * <h5 class='section'>Collection and Boolean Values:</h5>
         * <p class='bjava'>
         *      <jc>// Test boolean values</jc>
-        *      assertBean(myBean, <js>"enabled,visible"</js>, 
<js>"true,false"</js>);
+        *      <jsm>assertBean</jsm>(<jv>myBean</jv>, 
<js>"enabled,visible"</js>, <js>"true,false"</js>);
         *
         *      <jc>// Test enum collections</jc>
-        *      assertBean(myBean, <js>"statuses"</js>, 
<js>"[ACTIVE,PENDING]"</js>);
+        *      <jsm>assertBean</jsm>(<jv>myBean</jv>, <js>"statuses"</js>, 
<js>"[ACTIVE,PENDING]"</js>);
         * </p>
         *
         * <h5 class='section'>Value Syntax Rules:</h5>
@@ -371,19 +371,19 @@ public class Assertions2 {
         * <h5 class='section'>Basic Usage:</h5>
         * <p class='bjava'>
         *      <jc>// Test list of user beans</jc>
-        *      assertBeans(<jv>userList</jv>, <js>"name,age"</js>,
+        *      <jsm>assertBeans</jsm>(<jv>userList</jv>, <js>"name,age"</js>,
         *              <js>"John,25"</js>, <js>"Jane,30"</js>, 
<js>"Bob,35"</js>);
         * </p>
         *
         * <h5 class='section'>Complex Property Testing:</h5>
         * <p class='bjava'>
-        *      <jc>// Test nested properties across multiple beans</jc>
-        *      assertBeans(<jv>orderList</jv>, 
<js>"id,customer{name,email}"</js>,
+        *      <jc>// Test nested properties across multiple beans - orderList 
is a List&lt;Order&gt; where Order has getId() and getCustomer() returning 
Customer with getName() and getEmail()</jc>
+        *      <jsm>assertBeans</jsm>(<jv>orderList</jv>, 
<js>"id,customer{name,email}"</js>,
         *              <js>"1,{John,[email protected]}"</js>,
         *              <js>"2,{Jane,[email protected]}"</js>);
         *
-        *      <jc>// Test collection properties within beans</jc>
-        *      assertBeans(<jv>cartList</jv>, <js>"items{0{name}},total"</js>,
+        *      <jc>// Test collection properties within beans - cartList is a 
List&lt;ShoppingCart&gt; where ShoppingCart has getItems() returning 
List&lt;Product&gt; and getTotal()</jc>
+        *      <jsm>assertBeans</jsm>(<jv>cartList</jv>, 
<js>"items{0{name}},total"</js>,
         *              <js>"{{Laptop}},999.99"</js>,
         *              <js>"{{Phone}},599.99"</js>);
         * </p>
@@ -391,7 +391,7 @@ public class Assertions2 {
         * <h5 class='section'>Validation Testing:</h5>
         * <p class='bjava'>
         *      <jc>// Test validation results</jc>
-        *      assertBeans(<jv>validationErrors</jv>, 
<js>"field,message,code"</js>,
+        *      <jsm>assertBeans</jsm>(<jv>validationErrors</jv>, 
<js>"field,message,code"</js>,
         *              <js>"email,Invalid email format,E001"</js>,
         *              <js>"age,Must be 18 or older,E002"</js>);
         * </p>
@@ -399,7 +399,7 @@ public class Assertions2 {
          * <h5 class='section'>Collection Iteration Testing:</h5>
         * <p class='bjava'>
         *      <jc>// Test collection iteration within beans (#{...} 
syntax)</jc>
-        *      assertBeans(<jv>departmentList</jv>, 
<js>"name,employees{#{name}}"</js>,
+        *      <jsm>assertBeans</jsm>(<jv>departmentList</jv>, 
<js>"name,employees{#{name}}"</js>,
         *              <js>"Engineering,[{Alice},{Bob},{Charlie}]"</js>,
         *              <js>"Marketing,[{David},{Eve}]"</js>);
         * </p>
@@ -407,8 +407,8 @@ public class Assertions2 {
         * <h5 class='section'>Parser Result Testing:</h5>
         * <p class='bjava'>
         *      <jc>// Test parsed object collections</jc>
- *     <jk>var</jk> <jv>parsed</jv> = 
JsonParser.<jsf>DEFAULT</jsf>.parse(<jv>jsonArray</jv>, MyBean[].class);
- *     assertBeans(<jsm>Arrays.asList</jsm>(<jv>parsed</jv>), 
<js>"prop1,prop2"</js>,
+        *      <jk>var</jk> <jv>parsed</jv> = 
JsonParser.<jsf>DEFAULT</jsf>.parse(<jv>jsonArray</jv>, MyBean[].class);
+        *      
<jsm>assertBeans</jsm>(<jsm>Arrays.asList</jsm>(<jv>parsed</jv>), 
<js>"prop1,prop2"</js>,
         *              <js>"val1,val2"</js>, <js>"val3,val4"</js>);
         * </p>
         *
@@ -539,13 +539,13 @@ public class Assertions2 {
         * <h5 class='section'>Usage Examples:</h5>
         * <p class='bjava'>
         *      <jc>// Test that error message contains key information</jc>
-        *      <jsm>assertContains</jsm>(<js>"FileNotFoundException"</js>, 
exception);
+        *      <jsm>assertContains</jsm>(<js>"FileNotFoundException"</js>, 
<jv>exception</jv>);
         *
         *      <jc>// Test that object string representation contains expected 
data</jc>
-        *      <jsm>assertContains</jsm>(<js>"status=ACTIVE"</js>, user);
+        *      <jsm>assertContains</jsm>(<js>"status=ACTIVE"</js>, 
<jv>user</jv>);
         *
         *      <jc>// Test partial JSON/XML content</jc>
-        *      <jsm>assertContains</jsm>(<js>"\"name\":\"John\""</js>, 
jsonResponse);
+        *      <jsm>assertContains</jsm>(<js>"\"name\":\"John\""</js>, 
<jv>jsonResponse</jv>);
         * </p>
         *
         * @param expected The substring that must be present in the actual 
object's string representation
@@ -587,13 +587,13 @@ public class Assertions2 {
         * <h5 class='section'>Usage Examples:</h5>
         * <p class='bjava'>
         *      <jc>// Test that error contains multiple pieces of 
information</jc>
-        *      <jsm>assertContainsAll</jsm>(exception, 
<js>"FileNotFoundException"</js>, <js>"config.xml"</js>, <js>"/etc"</js>);
+        *      <jsm>assertContainsAll</jsm>(<jv>exception</jv>, 
<js>"FileNotFoundException"</js>, <js>"config.xml"</js>, <js>"/etc"</js>);
         *
         *      <jc>// Test that user object contains expected fields</jc>
-        *      <jsm>assertContainsAll</jsm>(user, <js>"name=John"</js>, 
<js>"age=30"</js>, <js>"status=ACTIVE"</js>);
+        *      <jsm>assertContainsAll</jsm>(<jv>user</jv>, 
<js>"name=John"</js>, <js>"age=30"</js>, <js>"status=ACTIVE"</js>);
         *
         *      <jc>// Test log output contains all required entries</jc>
-        *      <jsm>assertContainsAll</jsm>(logOutput, <js>"INFO"</js>, 
<js>"Started"</js>, <js>"Successfully"</js>);
+        *      <jsm>assertContainsAll</jsm>(<jv>logOutput</jv>, 
<js>"INFO"</js>, <js>"Started"</js>, <js>"Successfully"</js>);
         * </p>
         *
         * @param actual The object to test. Must not be null.
@@ -707,15 +707,15 @@ public class Assertions2 {
         * <p class='bjava'>
         *      <jc>// Test a Set using l() conversion</jc>
         *      Set&lt;String&gt; <jv>mySet</jv> = 
Set.<jsm>of</jsm>(<js>"a"</js>, <js>"b"</js>, <js>"c"</js>);
-        *      assertList(l(<jv>mySet</jv>), <js>"a"</js>, <js>"b"</js>, 
<js>"c"</js>);
+        *      <jsm>assertList</jsm>(<jsm>l</jsm>(<jv>mySet</jv>), 
<js>"a"</js>, <js>"b"</js>, <js>"c"</js>);
         *
         *      <jc>// Test an array using l() conversion</jc>
         *      String[] <jv>myArray</jv> = {<js>"x"</js>, <js>"y"</js>, 
<js>"z"</js>};
-        *      assertList(l(<jv>myArray</jv>), <js>"x"</js>, <js>"y"</js>, 
<js>"z"</js>);
+        *      <jsm>assertList</jsm>(<jsm>l</jsm>(<jv>myArray</jv>), 
<js>"x"</js>, <js>"y"</js>, <js>"z"</js>);
         *
         *      <jc>// Test a Stream using l() conversion</jc>
-        *      Stream&lt;String&gt; <jv>myStream</jv> = 
Stream.of(<js>"foo"</js>, <js>"bar"</js>);
-        *      assertList(l(<jv>myStream</jv>), <js>"foo"</js>, 
<js>"bar"</js>);
+        *      Stream&lt;String&gt; <jv>myStream</jv> = 
Stream.<jsm>of</jsm>(<js>"foo"</js>, <js>"bar"</js>);
+        *      <jsm>assertList</jsm>(<jsm>l</jsm>(<jv>myStream</jv>), 
<js>"foo"</js>, <js>"bar"</js>);
         * </p>
         *
         * <h5 class='section'>Comparison Modes:</h5>
@@ -723,27 +723,27 @@ public class Assertions2 {
         *
         * <h6 class='section'>1. String Comparison (Readable Format):</h6>
         * <p class='bjava'>
-        *      <jc>// Elements are converted to {@link Utils#r readable} 
format and compared as strings</jc>
- *     assertList(List.<jsm>of</jsm>(1, 2, 3), <js>"1"</js>, <js>"2"</js>, 
<js>"3"</js>);
- *     assertList(List.<jsm>of</jsm>("a", "b"), <js>"a"</js>, <js>"b"</js>);
+        *      <jc>// Elements are converted to strings using the bean 
converter and compared as strings</jc>
+        *      <jsm>assertList</jsm>(List.<jsm>of</jsm>(1, 2, 3), 
<js>"1"</js>, <js>"2"</js>, <js>"3"</js>);
+        *      <jsm>assertList</jsm>(List.<jsm>of</jsm>("a", "b"), 
<js>"a"</js>, <js>"b"</js>);
         * </p>
         *
         * <h6 class='section'>2. Predicate Testing (Functional 
Validation):</h6>
         * <p class='bjava'>
         *      <jc>// Use Predicate&lt;T&gt; for functional testing</jc>
         *      Predicate&lt;Integer&gt; <jv>greaterThanOne</jv> = <jv>x</jv> 
-&gt; <jv>x</jv> &gt; 1;
-        *      assertList(List.<jsm>of</jsm>(2, 3, 4), 
<jv>greaterThanOne</jv>, <jv>greaterThanOne</jv>, <jv>greaterThanOne</jv>);
+        *      <jsm>assertList</jsm>(List.<jsm>of</jsm>(2, 3, 4), 
<jv>greaterThanOne</jv>, <jv>greaterThanOne</jv>, <jv>greaterThanOne</jv>);
         *
         *      <jc>// Mix predicates with other comparison types</jc>
         *      Predicate&lt;String&gt; <jv>startsWithA</jv> = <jv>s</jv> -&gt; 
<jv>s</jv>.startsWith(<js>"a"</js>);
-        *      assertList(List.<jsm>of</jsm>(<js>"apple"</js>, 
<js>"banana"</js>), <jv>startsWithA</jv>, <js>"banana"</js>);
+        *      <jsm>assertList</jsm>(List.<jsm>of</jsm>(<js>"apple"</js>, 
<js>"banana"</js>), <jv>startsWithA</jv>, <js>"banana"</js>);
         * </p>
         *
         * <h6 class='section'>3. Object Equality (Direct Comparison):</h6>
         * <p class='bjava'>
         *      <jc>// Non-String, non-Predicate objects use 
<jsm>Objects.equals</jsm>() comparison</jc>
- *     assertList(List.<jsm>of</jsm>(1, 2, 3), 1, 2, 3); <jc>// Integer 
objects</jc>
- *     assertList(List.<jsm>of</jsm>(<jv>myBean1</jv>, <jv>myBean2</jv>), 
<jv>myBean1</jv>, <jv>myBean2</jv>); <jc>// Custom objects</jc>
+        *      <jsm>assertList</jsm>(List.<jsm>of</jsm>(1, 2, 3), 1, 2, 3); 
<jc>// Integer objects</jc>
+        *      <jsm>assertList</jsm>(List.<jsm>of</jsm>(<jv>myBean1</jv>, 
<jv>myBean2</jv>), <jv>myBean1</jv>, <jv>myBean2</jv>); <jc>// Custom 
objects</jc>
         * </p>
         *
         * @param actual The List to test. Must not be null. For other 
collection types, use {@link #l(Object)} to convert first.
@@ -985,7 +985,7 @@ public class Assertions2 {
         *      
<jsm>assertMatches</jsm>(<js>"\\d{1,3}(,\\d{3})*(\\.\\d{2})?"</js>, 
formattedPrice);
         *
         *      <jc>// Test multiline content with dotall mode</jc>
-        *      <jsm>assertMatches</jsm>(<js>".*error.*exception.*"</js>, 
multiLineLog);
+        *      <jsm>assertMatches</jsm>(<js>".*error.*exception.*"</js>, 
<jv>multiLineLog</jv>);
         * </p>
         *
         * @param pattern The regular expression pattern to match against. 
Supports "/i" and "/s" flags.
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/junit/BasicBeanConverter.java 
b/juneau-utest/src/test/java/org/apache/juneau/junit/BasicBeanConverter.java
index 558831669..5fbf6a042 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/junit/BasicBeanConverter.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/junit/BasicBeanConverter.java
@@ -96,7 +96,7 @@ import java.util.stream.*;
  *
  * <p>Default swapping support includes:</p>
  * <ul>
- *     <li><b>Optional:</b> Unwrapped to contained value or null</li>
+ *     <li><b>Optional:</b> Unwrapped to contained value or <jk>null</jk></li>
  *     <li><b>Supplier:</b> Called to get supplied value</li>
  *     <li><b>Future:</b> Extracts completed result or returns 
"&lt;pending&gt;" for incomplete futures</li>
  * </ul>
@@ -401,23 +401,23 @@ public class BasicBeanConverter implements BeanConverter {
         *
         * <h5 class='section'>Usage Example:</h5>
         * <p class='bjava'>
- *     <jk>var</jk> <jv>converter</jv> = 
BasicBeanConverter.<jsm>builder</jsm>()
- *             .defaultSettings()
- *             <jc>// Custom stringification for LocalDateTime</jc>
- *             .addStringifier(LocalDateTime.<jk>class</jk>, (<jp>dt</jp>, 
<jp>conv</jp>) ->
- *                     
<jp>dt</jp>.format(DateTimeFormatter.<jsf>ISO_LOCAL_DATE_TIME</jsf>))
+        *      <jk>var</jk> <jv>converter</jv> = 
BasicBeanConverter.<jsm>builder</jsm>()
+        *              .defaultSettings()
+        *              <jc>// Custom stringification for LocalDateTime</jc>
+        *              .addStringifier(LocalDateTime.<jk>class</jk>, 
(<jp>dt</jp>, <jp>conv</jp>) ->
+        *                      
<jp>dt</jp>.format(DateTimeFormatter.<jsf>ISO_LOCAL_DATE_TIME</jsf>))
         *
         *              <jc>// Custom collection handling for custom type</jc>
- *             .addListifier(MyIterable.<jk>class</jk>, (<jp>iter</jp>, 
<jp>conv</jp>) ->
- *                     <jp>iter</jp>.stream().collect(toList()))
+        *              .addListifier(MyIterable.<jk>class</jk>, 
(<jp>iter</jp>, <jp>conv</jp>) ->
+        *                      <jp>iter</jp>.stream().collect(toList()))
         *
         *              <jc>// Custom transformation for wrapper type</jc>
- *             .addSwapper(LazyValue.<jk>class</jk>, (<jp>lazy</jp>, 
<jp>conv</jp>) ->
- *                     <jp>lazy</jp>.isComputed() ? <jp>lazy</jp>.get() : null)
+        *              .addSwapper(LazyValue.<jk>class</jk>, (<jp>lazy</jp>, 
<jp>conv</jp>) ->
+        *                      <jp>lazy</jp>.isComputed() ? 
<jp>lazy</jp>.get() : <jk>null</jk>)
         *
         *              <jc>// Configure settings</jc>
- *             .addSetting(<jsf>SETTING_nullValue</jsf>, "NULL")
- *             .addSetting(<jsf>SETTING_fieldSeparator</jsf>, " | ")
+        *              .addSetting(<jsf>SETTING_nullValue</jsf>, 
<js>"NULL"</js>)
+        *              .addSetting(<jsf>SETTING_fieldSeparator</jsf>, <js>" | 
"</js>)
         *
         *              <jc>// Add default handlers for common types</jc>
         *              .defaultSettings()
@@ -534,7 +534,7 @@ public class BasicBeanConverter implements BeanConverter {
                 *
                 * <p>Property extractors enable custom property access 
patterns beyond standard JavaBean
                 * conventions. The converter tries extractors in registration 
order until one returns
-                * a non-null value. This allows for:</p>
+                * a non-<jk>null</jk> value. This allows for:</p>
                 * <ul>
                 *      <li><b>Custom data structures:</b> Special property 
access for non-standard objects</li>
                 *      <li><b>Database entities:</b> Property access via 
entity-specific methods</li>
@@ -628,6 +628,17 @@ public class BasicBeanConverter implements BeanConverter {
 
                        addSwapper(Optional.class, (bc, o) -> o.orElse(null));
                        addSwapper(Supplier.class, (bc, o) -> o.get());
+                       addSwapper(Future.class, (bc, future) -> {
+                               var f = (Future<?>)future;
+                               if (f.isDone() && !f.isCancelled()) {
+                                       try {
+                                               return f.get();
+                                       } catch (Exception e) {
+                                               return "<error: " + 
e.getMessage() + ">";
+                                       }
+                               }
+                               return f.isCancelled() ? "<cancelled>" : 
"<pending>";
+                       });
 
                        addPropertyExtractor(new 
PropertyExtractors.ObjectPropertyExtractor());
                        addPropertyExtractor(new 
PropertyExtractors.ListPropertyExtractor());
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/junit/BasicBeanConverter_Test.java
 
b/juneau-utest/src/test/java/org/apache/juneau/junit/BasicBeanConverter_Test.java
new file mode 100644
index 000000000..f48f15620
--- /dev/null
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/junit/BasicBeanConverter_Test.java
@@ -0,0 +1,431 @@
+// 
***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                
                                              *
+// *                                                                           
                                              *
+// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
+// *                                                                           
                                              *
+// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the 
License.                                              *
+// 
***************************************************************************************************************************
+package org.apache.juneau.junit;
+
+import static org.apache.juneau.junit.Assertions2.*;
+import static org.apache.juneau.junit.BasicBeanConverter.*;
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.time.*;
+import java.time.format.*;
+import java.util.*;
+import java.util.concurrent.*;
+
+import org.junit.jupiter.api.*;
+
+/**
+ * Unit tests for BasicBeanConverter.
+ */
+@DisplayName("BasicBeanConverter")
+public class BasicBeanConverter_Test extends TestBase {
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // Builder Tests
+       
//------------------------------------------------------------------------------------------------------------------
+
+       @Nested
+       @DisplayName("Builder")
+       class BuilderTest {
+
+               @Test
+               @DisplayName("a01_builder() creates new Builder instance")
+               void a01_builder_createsNewInstance() {
+                       var builder = BasicBeanConverter.builder();
+                       assertNotNull(builder);
+                       assertInstanceOf(BasicBeanConverter.Builder.class, 
builder);
+               }
+
+               @Test
+               @DisplayName("a02_build() creates BasicBeanConverter instance")
+               void a02_build_createsBasicBeanConverter() {
+                       var converter = BasicBeanConverter.builder().build();
+                       assertNotNull(converter);
+                       assertInstanceOf(BasicBeanConverter.class, converter);
+               }
+
+               @Test
+               @DisplayName("a03_defaultSettings() applies default 
configuration")
+               void a03_defaultSettings_appliesDefaults() {
+                       var converter = 
BasicBeanConverter.builder().defaultSettings().build();
+
+                       // Test that default stringifiers work
+                       assertEquals("test", converter.stringify("test"));
+                       assertEquals("123", converter.stringify(123));
+                       assertEquals("true", converter.stringify(true));
+                       assertEquals("[1,2,3]", 
converter.stringify(Arrays.asList(1, 2, 3)));
+
+                       // Test that default settings are applied
+                       assertEquals("<null>", converter.stringify(null));
+               }
+
+               @Test
+               @DisplayName("a04_addStringifier() adds custom stringifier")
+               void a04_addStringifier_addsCustomStringifier() {
+                       var converter = BasicBeanConverter.builder()
+                               .defaultSettings()
+                               .addStringifier(LocalDate.class, (conv, date) 
-> date.format(DateTimeFormatter.ISO_LOCAL_DATE))
+                               .build();
+
+                       var date = LocalDate.of(2023, 12, 25);
+                       assertEquals("2023-12-25", converter.stringify(date));
+               }
+
+               @Test
+               @DisplayName("a05_addListifier() adds custom listifier")
+               void a05_addListifier_addsCustomListifier() {
+                       var converter = BasicBeanConverter.builder()
+                               .defaultSettings()
+                               .addListifier(String.class, (conv, str) -> 
Arrays.asList((Object[])str.split(",")))
+                               .build();
+
+                       var result = converter.listify("a,b,c");
+                       assertEquals(Arrays.asList("a", "b", "c"), result);
+               }
+
+               @Test
+               @DisplayName("a06_addSwapper() adds custom swapper")
+               void a06_addSwapper_addsCustomSwapper() {
+                       var converter = BasicBeanConverter.builder()
+                               .defaultSettings()
+                               .addSwapper(Optional.class, (conv, opt) -> 
((Optional<?>)opt).orElse(null))
+                               .build();
+
+                       assertEquals("test", 
converter.stringify(Optional.of("test")));
+                       assertEquals("<null>", 
converter.stringify(Optional.empty()));
+               }
+
+               @Test
+               @DisplayName("a07_addPropertyExtractor() adds custom property 
extractor")
+               void a07_addPropertyExtractor_addsCustomExtractor() {
+                       var extractor = new PropertyExtractor() {
+                               @Override
+                               public boolean canExtract(BeanConverter 
converter, Object o, String name) {
+                                       return o instanceof TestBean && 
"custom".equals(name);
+                               }
+
+                               @Override
+                               public Object extract(BeanConverter converter, 
Object o, String name) {
+                                       return "custom value";
+                               }
+                       };
+
+                       var converter = BasicBeanConverter.builder()
+                               .defaultSettings()
+                               .addPropertyExtractor(extractor)
+                               .build();
+
+                       var bean = new TestBean("John", 30);
+                       assertEquals("custom value", 
converter.getProperty(bean, "custom"));
+               }
+
+               @Test
+               @DisplayName("a08_addSetting() adds custom setting")
+               void a08_addSetting_addsCustomSetting() {
+                       var converter = BasicBeanConverter.builder()
+                               .defaultSettings()
+                               .addSetting(SETTING_nullValue, "NULL")
+                               .build();
+
+                       assertEquals("NULL", converter.stringify(null));
+               }
+       }
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // Core Functionality Tests
+       
//------------------------------------------------------------------------------------------------------------------
+
+       @Nested
+       @DisplayName("Core Functionality")
+       class CoreFunctionalityTest {
+
+               private BasicBeanConverter converter;
+
+               @BeforeEach
+               void setUp() {
+                       converter = 
BasicBeanConverter.builder().defaultSettings().build();
+               }
+
+               @Test
+               @DisplayName("b01_stringify() handles null values")
+               void b01_stringify_handlesNull() {
+                       assertEquals("<null>", converter.stringify(null));
+               }
+
+               @Test
+               @DisplayName("b02_stringify() handles primitive types")
+               void b02_stringify_handlesPrimitives() {
+                       assertEquals("123", converter.stringify(123));
+                       assertEquals("true", converter.stringify(true));
+                       assertEquals("3.14", converter.stringify(3.14));
+                       assertEquals("c", converter.stringify('c'));
+               }
+
+               @Test
+               @DisplayName("b03_stringify() handles strings")
+               void b03_stringify_handlesStrings() {
+                       assertEquals("hello", converter.stringify("hello"));
+                       assertEquals("", converter.stringify(""));
+               }
+
+               @Test
+               @DisplayName("b04_stringify() handles collections")
+               void b04_stringify_handlesCollections() {
+                       assertEquals("[1,2,3]", 
converter.stringify(Arrays.asList(1, 2, 3)));
+                       assertEquals("[]", 
converter.stringify(Collections.emptyList()));
+                       // Set order is not guaranteed, so check length and 
content
+                       var setResult = converter.stringify(Set.of("a", "b", 
"c"));
+                       assertEquals(7, setResult.length()); // Should be 
"[x,y,z]" format
+                       assertTrue(setResult.contains("a"));
+                       assertTrue(setResult.contains("b"));
+                       assertTrue(setResult.contains("c"));
+               }
+
+               @Test
+               @DisplayName("b05_stringify() handles maps")
+               void b05_stringify_handlesMaps() {
+                       var map = Map.of("name", "John", "age", 30);
+                       var result = converter.stringify(map);
+                       assertTrue(result.contains("name=John"));
+                       assertTrue(result.contains("age=30"));
+                       assertTrue(result.startsWith("{"));
+                       assertTrue(result.endsWith("}"));
+               }
+
+               @Test
+               @DisplayName("b06_stringify() handles arrays")
+               void b06_stringify_handlesArrays() {
+                       assertEquals("[1,2,3]", converter.stringify(new 
int[]{1, 2, 3}));
+                       assertEquals("[a,b,c]", converter.stringify(new 
String[]{"a", "b", "c"}));
+                       assertEquals("[]", converter.stringify(new Object[0]));
+               }
+
+               @Test
+               @DisplayName("b07_stringify() handles dates")
+               void b07_stringify_handlesDates() {
+                       var date = Instant.parse("2023-12-25T10:15:30Z");
+                       var result = converter.stringify(date);
+                       assertEquals("2023-12-25T10:15:30Z", result);
+               }
+
+               @Test
+               @DisplayName("b08_listify() converts arrays to lists")
+               void b08_listify_convertsArrays() {
+                       var result = converter.listify(new String[]{"a", "b", 
"c"});
+                       assertEquals(Arrays.asList("a", "b", "c"), result);
+               }
+
+               @Test
+               @DisplayName("b09_listify() handles collections")
+               void b09_listify_handlesCollections() {
+                       var set = Set.of("a", "b", "c");
+                       var result = converter.listify(set);
+                       assertEquals(3, result.size());
+                       assertTrue(result.containsAll(Arrays.asList("a", "b", 
"c")));
+               }
+
+               @Test
+               @DisplayName("b10_listify() handles null")
+               void b10_listify_handlesNull() {
+                       assertNull(converter.listify(null));
+               }
+
+               @Test
+               @DisplayName("b11_canListify() returns correct values")
+               void b11_canListify_returnsCorrectValues() {
+                       assertTrue(converter.canListify(Arrays.asList(1, 2, 
3)));
+                       assertTrue(converter.canListify(new int[]{1, 2, 3}));
+                       assertTrue(converter.canListify(Set.of("a", "b")));
+                       assertFalse(converter.canListify("string"));
+                       assertFalse(converter.canListify(null));
+               }
+
+               @Test
+               @DisplayName("b12_swap() applies swappers")
+               void b12_swap_appliesSwappers() {
+                       // Test with Future swapper (should be in default 
settings)
+                       var future = CompletableFuture.completedFuture("test");
+                       var result = converter.swap(future);
+                       // Future swapper should extract the completed value
+                       assertEquals("test", result);
+               }
+       }
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // Property Access Tests
+       
//------------------------------------------------------------------------------------------------------------------
+
+       @Nested
+       @DisplayName("Property Access")
+       class PropertyAccessTest {
+
+               private BasicBeanConverter converter;
+
+               @BeforeEach
+               void setUp() {
+                       converter = 
BasicBeanConverter.builder().defaultSettings().build();
+               }
+
+               @Test
+               @DisplayName("c01_getProperty() accesses bean properties")
+               void c01_getProperty_accessesBeanProperties() {
+                       var bean = new TestBean("John", 30);
+
+                       assertEquals("John", converter.getProperty(bean, 
"name"));
+                       assertEquals(30, converter.getProperty(bean, "age"));
+               }
+
+               @Test
+               @DisplayName("c02_getProperty() handles null objects")
+               void c02_getProperty_handlesNull() {
+                       assertNull(converter.getProperty(null, "name"));
+               }
+
+               @Test
+               @DisplayName("c03_getProperty() throws for unknown properties")
+               void c03_getProperty_throwsForUnknownProperties() {
+                       var bean = new TestBean("John", 30);
+
+                       assertThrows(RuntimeException.class, () ->
+                               converter.getProperty(bean, "unknown"));
+               }
+       }
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // Settings Tests
+       
//------------------------------------------------------------------------------------------------------------------
+
+       @Nested
+       @DisplayName("Settings")
+       class SettingsTest {
+
+               @Test
+               @DisplayName("d01_nullValue setting changes null 
representation")
+               void d01_nullValue_changesNullRepresentation() {
+                       var converter = BasicBeanConverter.builder()
+                               .defaultSettings()
+                               .addSetting(SETTING_nullValue, "NULL")
+                               .build();
+
+                       assertEquals("NULL", converter.stringify(null));
+               }
+
+               @Test
+               @DisplayName("d02_fieldSeparator setting changes delimiter")
+               void d02_fieldSeparator_changesDelimiter() {
+                       var converter = BasicBeanConverter.builder()
+                               .defaultSettings()
+                               .addSetting(SETTING_fieldSeparator, " | ")
+                               .build();
+
+                       assertEquals("[1 | 2 | 3]", 
converter.stringify(Arrays.asList(1, 2, 3)));
+               }
+
+               @Test
+               @DisplayName("d03_collection prefix/suffix settings change 
brackets")
+               void d03_collectionBrackets_changeBrackets() {
+                       var converter = BasicBeanConverter.builder()
+                               .defaultSettings()
+                               .addSetting(SETTING_collectionPrefix, "(")
+                               .addSetting(SETTING_collectionSuffix, ")")
+                               .build();
+
+                       assertEquals("(1,2,3)", 
converter.stringify(Arrays.asList(1, 2, 3)));
+               }
+
+               @Test
+               @DisplayName("d04_map prefix/suffix settings change brackets")
+               void d04_mapBrackets_changeBrackets() {
+                       var converter = BasicBeanConverter.builder()
+                               .defaultSettings()
+                               .addSetting(SETTING_mapPrefix, "<")
+                               .addSetting(SETTING_mapSuffix, ">")
+                               .build();
+
+                       var map = Map.of("a", 1);
+                       var result = converter.stringify(map);
+                       assertTrue(result.startsWith("<"));
+                       assertTrue(result.endsWith(">"));
+               }
+
+               @Test
+               @DisplayName("d05_mapEntrySeparator setting changes key-value 
separator")
+               void d05_mapEntrySeparator_changesKeyValueSeparator() {
+                       var converter = BasicBeanConverter.builder()
+                               .defaultSettings()
+                               .addSetting(SETTING_mapEntrySeparator, ":")
+                               .build();
+
+                       var map = Map.of("name", "John");
+                       var result = converter.stringify(map);
+                       assertTrue(result.contains("name:John"));
+               }
+
+               @Test
+               @DisplayName("d06_classNameFormat setting changes class name 
format")
+               void d06_classNameFormat_changesFormat() {
+                       var converter = BasicBeanConverter.builder()
+                               .defaultSettings()
+                               .addSetting(SETTING_classNameFormat, "full")
+                               .build();
+
+                       var bean = new TestBean("John", 30);
+                       var result = converter.stringify(bean);
+                       
assertTrue(result.contains("org.apache.juneau.junit.BasicBeanConverter_Test$TestBean"));
+               }
+       }
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // Error Handling Tests
+       
//------------------------------------------------------------------------------------------------------------------
+
+       @Nested
+       @DisplayName("Error Handling")
+       class ErrorHandlingTest {
+
+               private BasicBeanConverter converter;
+
+               @BeforeEach
+               void setUp() {
+                       converter = 
BasicBeanConverter.builder().defaultSettings().build();
+               }
+
+               @Test
+               @DisplayName("e01_getProperty() with invalid property throws 
RuntimeException")
+               void e01_getProperty_invalidProperty_throwsException() {
+                       var bean = new TestBean("John", 30);
+
+                       var ex = assertThrows(RuntimeException.class, () ->
+                               converter.getProperty(bean, "invalidProperty"));
+                       assertContains("Property invalidProperty not found", 
ex.getMessage());
+               }
+       }
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // Test Helper Classes
+       
//------------------------------------------------------------------------------------------------------------------
+
+       public static class TestBean {
+               private String name;
+               private int age;
+
+               public TestBean(String name, int age) {
+                       this.name = name;
+                       this.age = age;
+               }
+
+               public String getName() { return name; }
+               public int getAge() { return age; }
+               public void setName(String name) { this.name = name; }
+               public void setAge(int age) { this.age = age; }
+       }
+}
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/junit/NestedTokenizer.java 
b/juneau-utest/src/test/java/org/apache/juneau/junit/NestedTokenizer.java
index 212582c28..c47abee49 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/junit/NestedTokenizer.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/junit/NestedTokenizer.java
@@ -55,7 +55,7 @@ import java.util.*;
  *     <jc>// nested[1] = Token{value="config", 
nested=[Token{value="timeout"}, Token{value="retries"}]}</jc>
  * </p>
  */
-public class NestedTokenizer {
+class NestedTokenizer {
 
        /**
         * Parser states for the finite state machine.
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/junit/NestedTokenizer_Test.java 
b/juneau-utest/src/test/java/org/apache/juneau/junit/NestedTokenizer_Test.java
index 223103129..bb1798545 100644
--- 
a/juneau-utest/src/test/java/org/apache/juneau/junit/NestedTokenizer_Test.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/junit/NestedTokenizer_Test.java
@@ -33,7 +33,7 @@ import org.junit.jupiter.api.*;
  *     <li>Token object functionality</li>
  * </ul>
  */
-class NestedTokenizer_Test {
+class NestedTokenizer_Test extends TestBase {
 
        
//------------------------------------------------------------------------------------------------------------------
        // Basic tokenization tests
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/junit/PropertyExtractors.java 
b/juneau-utest/src/test/java/org/apache/juneau/junit/PropertyExtractors.java
index 7cab1b153..ca8127af9 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/junit/PropertyExtractors.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/junit/PropertyExtractors.java
@@ -143,9 +143,9 @@ public class PropertyExtractors {
         *
         * <h5 class='section'>Additional Properties:</h5>
         * <ul>
-        *      <li><b>Numeric indices:</b> {@code "0"}, {@code "1"}, {@code 
"2"}, etc. for element access</li>
-        *      <li><b>Negative indices:</b> {@code "-1"}, {@code "-2"} for 
reverse indexing (from end)</li>
-        *      <li><b>Size properties:</b> {@code "length"} and {@code "size"} 
return collection size</li>
+        *      <li><b>Numeric indices:</b> <js>"0"</js>, <js>"1"</js>, 
<js>"2"</js>, etc. for element access</li>
+        *      <li><b>Negative indices:</b> <js>"-1"</js>, <js>"-2"</js> for 
reverse indexing (from end)</li>
+        *      <li><b>Size properties:</b> <js>"length"</js> and 
<js>"size"</js> return collection size</li>
         * </ul>
         *
         * <h5 class='section'>Supported Types:</h5>
@@ -184,8 +184,13 @@ public class PropertyExtractors {
                @Override
                public Object extract(BeanConverter converter, Object o, String 
name) {
                        var l = converter.listify(o);
-                       if (name.matches("-?\\d+"))
-                               return l.get(parseInt(name));
+                       if (name.matches("-?\\d+")) {
+                               var index = parseInt(name);
+                               if (index < 0) {
+                                       index = l.size() + index; // Convert 
negative index to positive
+                               }
+                               return l.get(index);
+                       }
                        if ("length".equals(name)) return l.size();
                        if ("size".equals(name)) return l.size();
                        return super.extract(converter, o, name);
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/junit/PropertyExtractors_Test.java
 
b/juneau-utest/src/test/java/org/apache/juneau/junit/PropertyExtractors_Test.java
new file mode 100644
index 000000000..e0811338d
--- /dev/null
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/junit/PropertyExtractors_Test.java
@@ -0,0 +1,359 @@
+// 
***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                
                                              *
+// *                                                                           
                                              *
+// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
+// *                                                                           
                                              *
+// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the 
License.                                              *
+// 
***************************************************************************************************************************
+package org.apache.juneau.junit;
+
+import static org.apache.juneau.junit.Assertions2.*;
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.util.*;
+import java.util.concurrent.*;
+
+import org.junit.jupiter.api.*;
+
+/**
+ * Unit tests for PropertyExtractors.
+ */
+@DisplayName("PropertyExtractors")
+class PropertyExtractors_Test extends TestBase {
+
+       private BasicBeanConverter converter;
+
+       @BeforeEach
+       void setUp() {
+               converter = 
BasicBeanConverter.builder().defaultSettings().build();
+       }
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // ObjectPropertyExtractor
+       
//------------------------------------------------------------------------------------------------------------------
+
+       @Nested
+       @DisplayName("ObjectPropertyExtractor")
+       class ObjectPropertyExtractorTest {
+
+               private PropertyExtractors.ObjectPropertyExtractor extractor = 
new PropertyExtractors.ObjectPropertyExtractor();
+
+               @Test
+               @DisplayName("canExtract() - always returns true")
+               void a01_canExtract_alwaysReturnsTrue() {
+                       assertTrue(extractor.canExtract(converter, new 
TestBean(), "name"));
+                       assertTrue(extractor.canExtract(converter, "string", 
"length"));
+                       assertTrue(extractor.canExtract(converter, 123, 
"value"));
+                       assertTrue(extractor.canExtract(converter, null, 
"anything"));
+               }
+
+               @Test
+               @DisplayName("extract() - getter methods")
+               void a02_extract_getterMethods() {
+                       var bean = new TestBean("John", 30, true);
+
+                       assertEquals("John", extractor.extract(converter, bean, 
"name"));
+                       assertEquals(30, extractor.extract(converter, bean, 
"age"));
+                       assertEquals(true, extractor.extract(converter, bean, 
"active"));
+               }
+
+               @Test
+               @DisplayName("extract() - boolean is* methods")
+               void a03_extract_booleanIsMethods() {
+                       var bean = new TestBean("John", 30, true);
+
+                       assertEquals(true, extractor.extract(converter, bean, 
"active"));
+               }
+
+               @Test
+               @DisplayName("extract() - public fields")
+               void a04_extract_publicFields() {
+                       var bean = new TestBeanWithFields();
+                       bean.publicField = "test value";
+
+                       assertEquals("test value", extractor.extract(converter, 
bean, "publicField"));
+               }
+
+               @Test
+               @DisplayName("extract() - inherited fields")
+               void a05_extract_inheritedFields() {
+                       var bean = new ChildBeanWithFields();
+                       bean.parentField = "parent value";
+                       bean.childField = "child value";
+
+                       assertEquals("parent value", 
extractor.extract(converter, bean, "parentField"));
+                       assertEquals("child value", 
extractor.extract(converter, bean, "childField"));
+               }
+
+               @Test
+               @DisplayName("extract() - method with property name")
+               void a06_extract_methodWithPropertyName() {
+                       var bean = new TestBeanWithMethods();
+
+                       assertEquals("custom method", 
extractor.extract(converter, bean, "customMethod"));
+               }
+
+               @Test
+               @DisplayName("extract() - Map-style get(String) method")
+               void a07_extract_mapStyleGetter() {
+                       var bean = new TestBeanWithMapGetter();
+
+                       assertEquals("mapped value", 
extractor.extract(converter, bean, "key1"));
+               }
+
+               @Test
+               @DisplayName("extract() - null object returns null")
+               void a08_extract_nullObject() {
+                       assertNull(extractor.extract(converter, null, 
"anything"));
+               }
+
+               @Test
+               @DisplayName("extract() - property not found throws 
RuntimeException")
+               void a09_extract_propertyNotFound() {
+                       var bean = new TestBean("John", 30, true);
+
+                       var ex = assertThrows(RuntimeException.class, () ->
+                               extractor.extract(converter, bean, 
"nonExistentProperty"));
+                       assertContains(ex.getMessage(), "Property 
nonExistentProperty not found on object of type TestBean");
+               }
+       }
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // ListPropertyExtractor
+       
//------------------------------------------------------------------------------------------------------------------
+
+       @Nested
+       @DisplayName("ListPropertyExtractor")
+       class ListPropertyExtractorTest {
+
+               private PropertyExtractors.ListPropertyExtractor extractor = 
new PropertyExtractors.ListPropertyExtractor();
+
+               @Test
+               @DisplayName("canExtract() - returns true for listifiable 
objects")
+               void b01_canExtract_listifiableObjects() {
+                       assertTrue(extractor.canExtract(converter, 
Arrays.asList("a", "b", "c"), "0"));
+                       assertTrue(extractor.canExtract(converter, new 
String[]{"a", "b", "c"}, "1"));
+                       assertTrue(extractor.canExtract(converter, Set.of("a", 
"b", "c"), "size"));
+                       assertFalse(extractor.canExtract(converter, "not 
listifiable", "0"));
+               }
+
+               @Test
+               @DisplayName("extract() - numeric indices")
+               void b02_extract_numericIndices() {
+                       var list = Arrays.asList("first", "second", "third");
+
+                       assertEquals("first", extractor.extract(converter, 
list, "0"));
+                       assertEquals("second", extractor.extract(converter, 
list, "1"));
+                       assertEquals("third", extractor.extract(converter, 
list, "2"));
+               }
+
+               @Test
+               @DisplayName("extract() - negative indices")
+               void b03_extract_negativeIndices() {
+                       var list = Arrays.asList("first", "second", "third");
+
+                       assertEquals("third", extractor.extract(converter, 
list, "-1"));
+                       assertEquals("second", extractor.extract(converter, 
list, "-2"));
+                       assertEquals("first", extractor.extract(converter, 
list, "-3"));
+               }
+
+               @Test
+               @DisplayName("extract() - arrays")
+               void b04_extract_arrays() {
+                       var array = new String[]{"a", "b", "c"};
+
+                       assertEquals("a", extractor.extract(converter, array, 
"0"));
+                       assertEquals("b", extractor.extract(converter, array, 
"1"));
+                       assertEquals("c", extractor.extract(converter, array, 
"2"));
+               }
+
+               @Test
+               @DisplayName("extract() - length property")
+               void b05_extract_lengthProperty() {
+                       var list = Arrays.asList("a", "b", "c");
+                       var array = new String[]{"a", "b", "c"};
+
+                       assertEquals(3, extractor.extract(converter, list, 
"length"));
+                       assertEquals(3, extractor.extract(converter, array, 
"length"));
+               }
+
+               @Test
+               @DisplayName("extract() - size property")
+               void b06_extract_sizeProperty() {
+                       var list = Arrays.asList("a", "b", "c");
+                       var set = Set.of("a", "b", "c");
+
+                       assertEquals(3, extractor.extract(converter, list, 
"size"));
+                       assertEquals(3, extractor.extract(converter, set, 
"size"));
+               }
+
+               @Test
+               @DisplayName("extract() - falls back to 
ObjectPropertyExtractor")
+               void b07_extract_fallbackToObjectPropertyExtractor() {
+                       var list = new ArrayList<>(Arrays.asList("a", "b", 
"c"));
+
+                       // Should fall back to ArrayList.isEmpty() method
+                       assertEquals(false, extractor.extract(converter, list, 
"empty"));
+               }
+       }
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // MapPropertyExtractor
+       
//------------------------------------------------------------------------------------------------------------------
+
+       @Nested
+       @DisplayName("MapPropertyExtractor")
+       class MapPropertyExtractorTest {
+
+               private PropertyExtractors.MapPropertyExtractor extractor = new 
PropertyExtractors.MapPropertyExtractor();
+
+               @Test
+               @DisplayName("canExtract() - returns true only for Map objects")
+               void c01_canExtract_mapObjects() {
+                       assertTrue(extractor.canExtract(converter, 
Map.of("key", "value"), "key"));
+                       assertTrue(extractor.canExtract(converter, new 
HashMap<>(), "size"));
+                       assertFalse(extractor.canExtract(converter, 
Arrays.asList("a", "b"), "0"));
+                       assertFalse(extractor.canExtract(converter, "not a 
map", "length"));
+               }
+
+               @Test
+               @DisplayName("extract() - direct key access")
+               void c02_extract_directKeyAccess() {
+                       var map = Map.of("name", "John", "age", 30, "active", 
true);
+
+                       assertEquals("John", extractor.extract(converter, map, 
"name"));
+                       assertEquals(30, extractor.extract(converter, map, 
"age"));
+                       assertEquals(true, extractor.extract(converter, map, 
"active"));
+               }
+
+               @Test
+               @DisplayName("extract() - size property")
+               void c03_extract_sizeProperty() {
+                       var map = Map.of("a", 1, "b", 2, "c", 3);
+
+                       assertEquals(3, extractor.extract(converter, map, 
"size"));
+               }
+
+               @Test
+               @DisplayName("extract() - empty map")
+               void c04_extract_emptyMap() {
+                       var map = new HashMap<String, Object>();
+
+                       assertEquals(0, extractor.extract(converter, map, 
"size"));
+
+                       // Non-existent key should fall back to 
ObjectPropertyExtractor and throw exception
+                       var ex = assertThrows(RuntimeException.class, () ->
+                               extractor.extract(converter, map, 
"nonExistentKey"));
+                       assertContains(ex.getMessage(), "Property 
nonExistentKey not found on object of type HashMap");
+               }
+
+               @Test
+               @DisplayName("extract() - Properties object")
+               void c05_extract_propertiesObject() {
+                       var props = new Properties();
+                       props.setProperty("config.timeout", "5000");
+                       props.setProperty("config.enabled", "true");
+
+                       assertEquals("5000", extractor.extract(converter, 
props, "config.timeout"));
+                       assertEquals("true", extractor.extract(converter, 
props, "config.enabled"));
+               }
+
+               @Test
+               @DisplayName("extract() - ConcurrentHashMap")
+               void c06_extract_concurrentHashMap() {
+                       var map = new ConcurrentHashMap<String, Object>();
+                       map.put("thread-safe", true);
+                       map.put("capacity", 16);
+
+                       assertEquals(true, extractor.extract(converter, map, 
"thread-safe"));
+                       assertEquals(16, extractor.extract(converter, map, 
"capacity"));
+                       assertEquals(2, extractor.extract(converter, map, 
"size"));
+               }
+
+               @Test
+               @DisplayName("extract() - key priority over JavaBean 
properties")
+               void c07_extract_keyPriorityOverJavaBeanProperties() {
+                       var map = new TestMapWithMethods();
+                       map.put("customProperty", "map value");
+
+                       // Map key should take priority over the 
getCustomProperty() method
+                       assertEquals("map value", extractor.extract(converter, 
map, "customProperty"));
+               }
+
+               @Test
+               @DisplayName("extract() - falls back to 
ObjectPropertyExtractor")
+               void c08_extract_fallbackToObjectPropertyExtractor() {
+                       var map = new TestMapWithMethods();
+
+                       // Should fall back to HashMap.isEmpty() method since 
"empty" is not a key
+                       assertEquals(true, extractor.extract(converter, map, 
"empty"));
+               }
+       }
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // Test Helper Classes
+       
//------------------------------------------------------------------------------------------------------------------
+
+       public static class TestBean {
+               private String name;
+               private int age;
+               private boolean active;
+
+               public TestBean() {}
+
+               public TestBean(String name, int age, boolean active) {
+                       this.name = name;
+                       this.age = age;
+                       this.active = active;
+               }
+
+               public String getName() { return name; }
+               public int getAge() { return age; }
+               public boolean isActive() { return active; }
+
+               public void setName(String name) { this.name = name; }
+               public void setAge(int age) { this.age = age; }
+               public void setActive(boolean active) { this.active = active; }
+       }
+
+       public static class TestBeanWithFields {
+               public String publicField;
+               @SuppressWarnings("unused")
+               private String privateField = "private";
+       }
+
+       public static class ParentBeanWithFields {
+               public String parentField;
+       }
+
+       public static class ChildBeanWithFields extends ParentBeanWithFields {
+               public String childField;
+       }
+
+       public static class TestBeanWithMethods {
+               public String customMethod() {
+                       return "custom method";
+               }
+       }
+
+       public static class TestBeanWithMapGetter {
+               private Map<String, String> data = Map.of("key1", "mapped 
value", "key2", "another value");
+
+               public String get(String key) {
+                       return data.get(key);
+               }
+       }
+
+       public static class TestMapWithMethods extends HashMap<String, Object> {
+               private static final long serialVersionUID = 1L;
+
+               public String getCustomProperty() {
+                       return "method value";
+               }
+       }
+}
diff --git a/juneau-utest/src/test/java/org/apache/juneau/junit/TestBase.java 
b/juneau-utest/src/test/java/org/apache/juneau/junit/TestBase.java
new file mode 100644
index 000000000..e59fbd259
--- /dev/null
+++ b/juneau-utest/src/test/java/org/apache/juneau/junit/TestBase.java
@@ -0,0 +1,26 @@
+// 
***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                
                                              *
+// *                                                                           
                                              *
+// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
+// *                                                                           
                                              *
+// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the 
License.                                              *
+// 
***************************************************************************************************************************
+package org.apache.juneau.junit;
+
+import org.junit.jupiter.api.*;
+
+/**
+ * Base test class that provides common test configuration for all test 
classes in the junit package.
+ *
+ * <p>This class configures test method ordering to use method names, ensuring 
consistent and predictable
+ * test execution order across all test classes in the package.</p>
+ */
+@TestMethodOrder(MethodOrderer.MethodName.class)
+public abstract class TestBase {
+       // Base class for common test configuration
+}
diff --git a/juneau-utest/src/test/java/org/apache/juneau/junit/Utils.java 
b/juneau-utest/src/test/java/org/apache/juneau/junit/Utils.java
index f5071b561..782d040cc 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/junit/Utils.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/junit/Utils.java
@@ -52,10 +52,8 @@ import org.opentest4j.*;
  * </p>
  *
  * <p><b>Thread Safety:</b> All methods in this class are thread-safe as they 
are stateless static methods.
- *
- * @since 9.2.0
  */
-public class Utils {
+class Utils {
 
        /**
         * Converts an array to a {@link List} of objects.
@@ -120,7 +118,7 @@ public class Utils {
         * @param <T> The argument data type.
         * @param name The argument name for error reporting.
         * @param o The object to validate.
-        * @return The same argument if not null.
+        * @return The same argument if not <jk>null</jk>.
         * @throws IllegalArgumentException If the argument is null.
         */
        public static final <T> T assertArgNotNull(String name, T o) throws 
IllegalArgumentException {
@@ -431,7 +429,7 @@ public class Utils {
         * Returns the simple class name of an object, or null if the object is 
null.
         *
         * <p>This method provides a safe way to get type information for 
debugging and logging.
-        * It handles null values gracefully by returning null instead of 
throwing an exception.
+        * It handles <jk>null</jk> values gracefully by returning 
<jk>null</jk> instead of throwing an exception.
         *
         * <h5 class='section'>Example:</h5>
         * <p class='bjava'>
@@ -441,7 +439,7 @@ public class Utils {
         * </p>
         *
         * @param o The object to get the type name for.
-        * @return The simple class name of the object, or null if the object 
is null.
+        * @return The simple class name of the object, or <jk>null</jk> if the 
object is <jk>null</jk>.
         */
        public static String t(Object o) {
                return o == null ? null : o.getClass().getSimpleName();
diff --git a/juneau-utest/src/test/java/org/apache/juneau/junit/Utils_Test.java 
b/juneau-utest/src/test/java/org/apache/juneau/junit/Utils_Test.java
index 2cb2b7b60..7b4c3fc14 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/junit/Utils_Test.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/junit/Utils_Test.java
@@ -13,6 +13,7 @@
 package org.apache.juneau.junit;
 
 import static org.apache.juneau.junit.Utils.*;
+import static org.apache.juneau.junit.Assertions2.*;
 import static org.junit.jupiter.api.Assertions.*;
 
 import java.util.*;
@@ -28,7 +29,7 @@ import org.junit.jupiter.api.*;
  * utility method categories.
  */
 @DisplayName("Utility Methods")
-class Utils_Test {
+class Utils_Test extends TestBase {
 
        // 
====================================================================================================
        // Array Conversion Tests
@@ -62,13 +63,12 @@ class Utils_Test {
                // Empty array
                int[] emptyArray = {};
                var result = arrayToList(emptyArray);
-               assertTrue(result.isEmpty());
+               assertEmpty(result);
 
                // Single element
                String[] singleElement = {"single"};
                result = arrayToList(singleElement);
-               assertEquals(1, result.size());
-               assertEquals("single", result.get(0));
+               assertList(result, "single");
        }
 
        @Test
@@ -89,18 +89,12 @@ class Utils_Test {
                // Boolean array
                boolean[] boolArray = {true, false, true};
                var result = arrayToList(boolArray);
-               assertEquals(3, result.size());
-               assertEquals(true, result.get(0));
-               assertEquals(false, result.get(1));
-               assertEquals(true, result.get(2));
+               assertList(result, "true","false","true");
 
                // Double array
                double[] doubleArray = {1.5, 2.7, 3.14};
                result = arrayToList(doubleArray);
-               assertEquals(3, result.size());
-               assertEquals(1.5, result.get(0));
-               assertEquals(2.7, result.get(1));
-               assertEquals(3.14, result.get(2));
+               assertList(result, "1.5","2.7","3.14");
        }
 
        // 
====================================================================================================
@@ -167,8 +161,8 @@ class Utils_Test {
        @DisplayName("assertEqualsFailed() - Basic error creation")
        void c01_assertEqualsFailedBasic() {
                var error = assertEqualsFailed("expected", "actual", null);
-               assertTrue(error.getMessage().contains("expected: <expected>"));
-               assertTrue(error.getMessage().contains("but was: <actual>"));
+               assertContains("expected: <expected>", error.getMessage());
+               assertContains("but was: <actual>", error.getMessage());
                assertEquals("expected", error.getExpected().getValue());
                assertEquals("actual", error.getActual().getValue());
        }
@@ -178,21 +172,19 @@ class Utils_Test {
        void c02_assertEqualsFailedWithMessage() {
                var msgSupplier = fs("Custom context message");
                var error = assertEqualsFailed(100, 200, msgSupplier);
-               assertTrue(error.getMessage().contains("Custom context 
message"));
-               assertTrue(error.getMessage().contains("expected: <100>"));
-               assertTrue(error.getMessage().contains("but was: <200>"));
+               assertContains("Custom context message", error.getMessage());
        }
 
        @Test
        @DisplayName("assertEqualsFailed() - Null values")
        void c03_assertEqualsFailedNullValues() {
                var error = assertEqualsFailed(null, "actual", null);
-               assertTrue(error.getMessage().contains("expected: <null>"));
-               assertTrue(error.getMessage().contains("but was: <actual>"));
+               assertContains("expected: <null>", error.getMessage());
+               assertContains("but was: <actual>", error.getMessage());
 
                error = assertEqualsFailed("expected", null, null);
-               assertTrue(error.getMessage().contains("expected: <expected>"));
-               assertTrue(error.getMessage().contains("but was: <null>"));
+               assertContains("expected: <expected>", error.getMessage());
+               assertContains("but was: <null>", error.getMessage());
        }
 
        // 
====================================================================================================
@@ -333,15 +325,15 @@ class Utils_Test {
        @DisplayName("f() - Complex parameter types")
        void f03_fComplexParameters() {
                // Test with Boolean
-               assertEquals("Flag: true", f("Flag: {0}", true));
-               assertEquals("Flag: false", f("Flag: {0}", false));
+               assertString(f("Flag: {0}", true), "Flag: true");
+               assertString(f("Flag: {0}", false), "Flag: false");
 
                // Test with List
                var list = Arrays.asList("a", "b", "c");
-               assertEquals("List: [a, b, c]", f("List: {0}", list));
+               assertString(f("List: {0}", list), "List: [a, b, c]");
 
                // Test with mixed types
-               assertEquals("User Alice (age 25) is active: true", f("User {0} 
(age {1}) is active: {2}", "Alice", 25, true));
+               assertString(f("User {0} (age {1}) is active: {2}", "Alice", 
25, true), "User Alice (age 25) is active: true");
        }
 
        @Test
@@ -484,11 +476,11 @@ class Utils_Test {
        @Test
        @DisplayName("t() - Various object types")
        void i01_tVariousTypes() {
-               assertEquals("String", t("hello"));
-               assertEquals("Integer", t(42));
-               assertEquals("ArrayList", t(new ArrayList<>()));
-               assertEquals("HashMap", t(new HashMap<>()));
-               assertEquals("Pattern", t(Pattern.compile("test")));
+               assertString(t("hello"), "String");
+               assertString(t(42), "Integer");
+               assertString(t(new ArrayList<>()), "ArrayList");
+               assertString(t(new HashMap<>()), "HashMap");
+               assertString(t(Pattern.compile("test")), "Pattern");
        }
 
        @Test
@@ -500,9 +492,9 @@ class Utils_Test {
        @Test
        @DisplayName("t() - Array types")
        void i03_tArrayTypes() {
-               assertEquals("String[]", t(new String[0]));
-               assertEquals("int[]", t(new int[0]));
-               assertEquals("Object[]", t(new Object[0]));
+               assertString(t(new String[0]), "String[]");
+               assertString(t(new int[0]), "int[]");
+               assertString(t(new Object[0]), "Object[]");
        }
 
        // 
====================================================================================================

Reply via email to