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<Product> 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<DataObject> 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<String></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<Order> 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<User> 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<User> 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<Order> 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<Customer> 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<User></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<Product> 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<ValidationError> 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 <NULL> syntax</jc>
- * assertBean(myBean, <js>"mapWithNullKey{<NULL>}"</js>,
<js>"{nullKeyValue}"</js>);
+ * <jsm>assertBean</jsm>(<jv>myBean</jv>,
<js>"mapWithNullKey{<NULL>}"</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<Order> 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<ShoppingCart> where ShoppingCart has getItems() returning
List<Product> 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<String> <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<String> <jv>myStream</jv> =
Stream.of(<js>"foo"</js>, <js>"bar"</js>);
- * assertList(l(<jv>myStream</jv>), <js>"foo"</js>,
<js>"bar"</js>);
+ * Stream<String> <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<T> for functional testing</jc>
* Predicate<Integer> <jv>greaterThanOne</jv> = <jv>x</jv>
-> <jv>x</jv> > 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<String> <jv>startsWithA</jv> = <jv>s</jv> ->
<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
"<pending>" 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[]");
}
//
====================================================================================================