You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2020/07/01 17:29:13 UTC

[commons-text] branch master updated: Sort members.

This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-text.git


The following commit(s) were added to refs/heads/master by this push:
     new b219b93  Sort members.
b219b93 is described below

commit b219b934e661cd26aac4b79ce0dd5a8a8d2c56ca
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Wed Jul 1 13:29:07 2020 -0400

    Sort members.
---
 .../apache/commons/text/AlphabetConverterTest.java |  192 +-
 .../commons/text/CharacterPredicatesTest.java      |   84 +-
 .../commons/text/ExtendedMessageFormatTest.java    |  580 ++--
 .../apache/commons/text/FormattableUtilsTest.java  |  140 +-
 .../commons/text/RandomStringGeneratorTest.java    |  230 +-
 .../commons/text/StrBuilderAppendInsertTest.java   | 1114 ++++----
 .../org/apache/commons/text/StrBuilderTest.java    | 2764 ++++++++++----------
 .../org/apache/commons/text/StrLookupTest.java     |   76 +-
 .../org/apache/commons/text/StrMatcherTest.java    |  198 +-
 .../apache/commons/text/StrSubstitutorTest.java    |  916 +++----
 .../org/apache/commons/text/StrTokenizerTest.java  |  490 ++--
 .../apache/commons/text/StringEscapeUtilsTest.java |  760 +++---
 ...ubstitutorWithInterpolatorStringLookupTest.java |   28 +-
 .../apache/commons/text/StringTokenizerTest.java   |  492 ++--
 .../text/TextStringBuilderAppendInsertTest.java    | 1084 ++++----
 .../org/apache/commons/text/WordUtilsTest.java     |  496 ++--
 16 files changed, 4822 insertions(+), 4822 deletions(-)

diff --git a/src/test/java/org/apache/commons/text/AlphabetConverterTest.java b/src/test/java/org/apache/commons/text/AlphabetConverterTest.java
index e88d5e1..28983f2 100644
--- a/src/test/java/org/apache/commons/text/AlphabetConverterTest.java
+++ b/src/test/java/org/apache/commons/text/AlphabetConverterTest.java
@@ -56,29 +56,18 @@ public class AlphabetConverterTest {
     private static Integer[] doNotEncodeCodepoints = {32, 97, 98, 99}; // space, a, b, c
 
     @Test
-    public void encodeFailureTest() {
-        assertThatThrownBy(() -> {
-            test(binary, numbers, empty, "3");
-        }).isInstanceOf(UnsupportedEncodingException.class).hasMessage("Couldn't find encoding for '3' in 3");
-    }
-
-    @Test
     public void binaryTest() throws UnsupportedEncodingException {
         test(binary, numbers, empty, "0", "1", "10", "11");
         test(numbers, binary, empty, "12345", "0");
         test(lowerCaseEnglish, binary, empty, "abc", "a");
     }
 
-    @Test
-    public void hebrewTest() throws UnsupportedEncodingException {
-        test(hebrew, binary, empty, "\u05d0", "\u05e2",
-                "\u05d0\u05dc\u05e3_\u05d0\u05d5\u05d4\u05d1\u05dc_\u05d1\u05d9\u05ea_\u05d6\u05d4_\u05d1\u05d9\u05ea_"
-                + "\u05d2\u05d9\u05de\u05dc_\u05d6\u05d4_\u05db\u05de\u05dc_\u05d2\u05d3\u05d5\u05dc");
-        test(hebrew, numbers, empty, "\u05d0", "\u05e2",
-                "\u05d0\u05dc\u05e3_\u05d0\u05d5\u05d4\u05d1\u05dc_\u05d1\u05d9\u05ea_\u05d6\u05d4_\u05d1\u05d9\u05ea_"
-                + "\u05d2\u05d9\u05de\u05dc_\u05d6\u05d4_\u05db\u05de\u05dc_\u05d2\u05d3\u05d5\u05dc");
-        test(numbers, hebrew, empty, "123456789", "1", "5");
-        test(lowerCaseEnglish, hebrew, empty, "this is a test");
+    private AlphabetConverter createJavadocExample() {
+        final Character[] original = {'a', 'b', 'c', 'd'};
+        final Character[] encoding = {'0', '1', 'd'};
+        final Character[] doNotEncode = {'d'};
+
+        return AlphabetConverter.createConverterFromChars(original, encoding, doNotEncode);
     }
 
     @Test
@@ -89,12 +78,23 @@ public class AlphabetConverterTest {
                 "this will be converted but 12345 and this will be");
     }
 
-    private AlphabetConverter createJavadocExample() {
-        final Character[] original = {'a', 'b', 'c', 'd'};
-        final Character[] encoding = {'0', '1', 'd'};
-        final Character[] doNotEncode = {'d'};
+    @Test
+    public void encodeFailureTest() {
+        assertThatThrownBy(() -> {
+            test(binary, numbers, empty, "3");
+        }).isInstanceOf(UnsupportedEncodingException.class).hasMessage("Couldn't find encoding for '3' in 3");
+    }
 
-        return AlphabetConverter.createConverterFromChars(original, encoding, doNotEncode);
+    @Test
+    public void hebrewTest() throws UnsupportedEncodingException {
+        test(hebrew, binary, empty, "\u05d0", "\u05e2",
+                "\u05d0\u05dc\u05e3_\u05d0\u05d5\u05d4\u05d1\u05dc_\u05d1\u05d9\u05ea_\u05d6\u05d4_\u05d1\u05d9\u05ea_"
+                + "\u05d2\u05d9\u05de\u05dc_\u05d6\u05d4_\u05db\u05de\u05dc_\u05d2\u05d3\u05d5\u05dc");
+        test(hebrew, numbers, empty, "\u05d0", "\u05e2",
+                "\u05d0\u05dc\u05e3_\u05d0\u05d5\u05d4\u05d1\u05dc_\u05d1\u05d9\u05ea_\u05d6\u05d4_\u05d1\u05d9\u05ea_"
+                + "\u05d2\u05d9\u05de\u05dc_\u05d6\u05d4_\u05db\u05de\u05dc_\u05d2\u05d3\u05d5\u05dc");
+        test(numbers, hebrew, empty, "123456789", "1", "5");
+        test(lowerCaseEnglish, hebrew, empty, "this is a test");
     }
 
     /*
@@ -112,41 +112,19 @@ public class AlphabetConverterTest {
     }
 
     @Test
-    public void unexpectedEndwhileDecodingTest() {
-        final String toDecode = "00d01d0";
+    public void missingDoNotEncodeLettersFromEncodingTest() {
         assertThatThrownBy(() -> {
-            final AlphabetConverter ac = createJavadocExample();
-            ac.decode(toDecode);
-        }).isInstanceOf(UnsupportedEncodingException.class).hasMessage(
-                "Unexpected end of string while decoding " + toDecode);
+            AlphabetConverter.createConverterFromChars(englishAndNumbers, lowerCaseEnglish, numbers);
+        }).isInstanceOf(IllegalArgumentException.class).hasMessage(
+                "Can not use 'do not encode' list because encoding alphabet does not contain '0'");
     }
 
     @Test
-    public void unexpectedStringWhileDecodingTest() {
-        final String toDecode = "00XX";
+    public void missingDoNotEncodeLettersFromOriginalTest() {
         assertThatThrownBy(() -> {
-            final AlphabetConverter ac = createJavadocExample();
-            ac.decode(toDecode);
-        }).isInstanceOf(UnsupportedEncodingException.class).hasMessage(
-                "Unexpected string without decoding (XX) in " + toDecode);
-    }
-
-    /*
-     * Test constructor from code points
-     */
-    @Test
-    public void unicodeTest() throws UnsupportedEncodingException {
-        final AlphabetConverter ac = AlphabetConverter.createConverter(unicode, lowerCaseEnglishCodepoints,
-                doNotEncodeCodepoints);
-
-        assertThat(ac.getEncodedCharLength()).isEqualTo(2);
-
-        final String original = "\u8a43\u8a45 \u8dce ab \u8dc3 c \u8983";
-        final String encoded = ac.encode(original);
-        final String decoded = ac.decode(encoded);
-
-        assertThat(decoded).as("Encoded '" + original + "' into '" + encoded + "', but decoded into '" + decoded + "'")
-            .isEqualTo(original);
+            AlphabetConverter.createConverterFromChars(lowerCaseEnglish, englishAndNumbers, numbers);
+        }).isInstanceOf(IllegalArgumentException.class).hasMessage(
+                "Can not use 'do not encode' list because original alphabet does not contain '0'");
     }
 
     @Test
@@ -168,22 +146,6 @@ public class AlphabetConverterTest {
                 "Must have at least two encoding characters (excluding those in the 'do not encode' list), but has 1");
     }
 
-    @Test
-    public void missingDoNotEncodeLettersFromEncodingTest() {
-        assertThatThrownBy(() -> {
-            AlphabetConverter.createConverterFromChars(englishAndNumbers, lowerCaseEnglish, numbers);
-        }).isInstanceOf(IllegalArgumentException.class).hasMessage(
-                "Can not use 'do not encode' list because encoding alphabet does not contain '0'");
-    }
-
-    @Test
-    public void missingDoNotEncodeLettersFromOriginalTest() {
-        assertThatThrownBy(() -> {
-            AlphabetConverter.createConverterFromChars(lowerCaseEnglish, englishAndNumbers, numbers);
-        }).isInstanceOf(IllegalArgumentException.class).hasMessage(
-                "Can not use 'do not encode' list because original alphabet does not contain '0'");
-    }
-
     private void test(final Character[] originalChars, final Character[] encodingChars,
             final Character[] doNotEncodeChars, final String... strings) throws UnsupportedEncodingException {
 
@@ -223,14 +185,16 @@ public class AlphabetConverterTest {
     }
 
     @Test
-    public void testCreateConverterFromCharsWithNullAndNull() {
-        assertThatIllegalArgumentException().isThrownBy(() -> {
-            final Character[] characterArray = new Character[2];
-            characterArray[0] = '$';
-            characterArray[1] = characterArray[0];
+    public void testCreateConverterFromCharsAndEquals() {
+        final Character[] characterArray = new Character[2];
+        final char charOne = '+';
+        final Character character = '+';
+        characterArray[0] = character;
+        characterArray[1] = characterArray[0];
+        final AlphabetConverter alphabetConverter = AlphabetConverter.createConverterFromChars(characterArray,
+                characterArray, characterArray);
 
-            AlphabetConverter.createConverterFromChars(characterArray, null, null);
-        });
+        assertThat(alphabetConverter.equals(charOne)).isFalse();
     }
 
     @Test
@@ -245,6 +209,17 @@ public class AlphabetConverterTest {
     }
 
     @Test
+    public void testCreateConverterFromCharsWithNullAndNull() {
+        assertThatIllegalArgumentException().isThrownBy(() -> {
+            final Character[] characterArray = new Character[2];
+            characterArray[0] = '$';
+            characterArray[1] = characterArray[0];
+
+            AlphabetConverter.createConverterFromChars(characterArray, null, null);
+        });
+    }
+
+    @Test
     public void testCreateConverterFromMapAndEquals() {
         final Map<Integer, String> hashMap = new HashMap<>();
         final AlphabetConverter alphabetConverter = AlphabetConverter.createConverterFromMap(hashMap);
@@ -256,6 +231,15 @@ public class AlphabetConverterTest {
     }
 
     @Test
+    public void testDecodeReturningNull() throws UnsupportedEncodingException {
+        final Map<Integer, String> map = new HashMap<>();
+        final AlphabetConverter alphabetConverter = AlphabetConverter.createConverterFromMap(map);
+        alphabetConverter.decode(null);
+
+        assertThat(alphabetConverter.getEncodedCharLength()).isEqualTo(1);
+    }
+
+    @Test
     public void testEquals() {
         final Character[] characterArray = new Character[2];
         final Character character = 'R';
@@ -271,6 +255,15 @@ public class AlphabetConverterTest {
     }
 
     @Test
+    public void testEqualsWithNull() {
+        final Character[] characterArray = new Character[0];
+        final AlphabetConverter alphabetConverter = AlphabetConverter.createConverterFromChars(characterArray, null,
+                null);
+
+        assertThat(alphabetConverter.equals(null)).isFalse();
+    }
+
+    @Test
     public void testEqualsWithSameObject() {
         final Character[] characterArray = new Character[2];
         final Character character = 'R';
@@ -283,34 +276,41 @@ public class AlphabetConverterTest {
     }
 
     @Test
-    public void testEqualsWithNull() {
-        final Character[] characterArray = new Character[0];
-        final AlphabetConverter alphabetConverter = AlphabetConverter.createConverterFromChars(characterArray, null,
-                null);
-
-        assertThat(alphabetConverter.equals(null)).isFalse();
+    public void unexpectedEndwhileDecodingTest() {
+        final String toDecode = "00d01d0";
+        assertThatThrownBy(() -> {
+            final AlphabetConverter ac = createJavadocExample();
+            ac.decode(toDecode);
+        }).isInstanceOf(UnsupportedEncodingException.class).hasMessage(
+                "Unexpected end of string while decoding " + toDecode);
     }
 
     @Test
-    public void testCreateConverterFromCharsAndEquals() {
-        final Character[] characterArray = new Character[2];
-        final char charOne = '+';
-        final Character character = '+';
-        characterArray[0] = character;
-        characterArray[1] = characterArray[0];
-        final AlphabetConverter alphabetConverter = AlphabetConverter.createConverterFromChars(characterArray,
-                characterArray, characterArray);
-
-        assertThat(alphabetConverter.equals(charOne)).isFalse();
+    public void unexpectedStringWhileDecodingTest() {
+        final String toDecode = "00XX";
+        assertThatThrownBy(() -> {
+            final AlphabetConverter ac = createJavadocExample();
+            ac.decode(toDecode);
+        }).isInstanceOf(UnsupportedEncodingException.class).hasMessage(
+                "Unexpected string without decoding (XX) in " + toDecode);
     }
 
+    /*
+     * Test constructor from code points
+     */
     @Test
-    public void testDecodeReturningNull() throws UnsupportedEncodingException {
-        final Map<Integer, String> map = new HashMap<>();
-        final AlphabetConverter alphabetConverter = AlphabetConverter.createConverterFromMap(map);
-        alphabetConverter.decode(null);
+    public void unicodeTest() throws UnsupportedEncodingException {
+        final AlphabetConverter ac = AlphabetConverter.createConverter(unicode, lowerCaseEnglishCodepoints,
+                doNotEncodeCodepoints);
 
-        assertThat(alphabetConverter.getEncodedCharLength()).isEqualTo(1);
+        assertThat(ac.getEncodedCharLength()).isEqualTo(2);
+
+        final String original = "\u8a43\u8a45 \u8dce ab \u8dc3 c \u8983";
+        final String encoded = ac.encode(original);
+        final String decoded = ac.decode(encoded);
+
+        assertThat(decoded).as("Encoded '" + original + "' into '" + encoded + "', but decoded into '" + decoded + "'")
+            .isEqualTo(original);
     }
 
 }
diff --git a/src/test/java/org/apache/commons/text/CharacterPredicatesTest.java b/src/test/java/org/apache/commons/text/CharacterPredicatesTest.java
index a6ff815..4a53c6b 100644
--- a/src/test/java/org/apache/commons/text/CharacterPredicatesTest.java
+++ b/src/test/java/org/apache/commons/text/CharacterPredicatesTest.java
@@ -26,34 +26,45 @@ import org.junit.jupiter.api.Test;
 public class CharacterPredicatesTest {
 
     @Test
-    public void testLetters() {
-        assertThat(CharacterPredicates.LETTERS.test('a')).isTrue();
-        assertThat(CharacterPredicates.LETTERS.test('Z')).isTrue();
+    public void testArabicNumerals() {
+        assertThat(CharacterPredicates.ARABIC_NUMERALS.test('0')).isTrue();
+        assertThat(CharacterPredicates.ARABIC_NUMERALS.test('1')).isTrue();
+        assertThat(CharacterPredicates.ARABIC_NUMERALS.test('9')).isTrue();
 
-        assertThat(CharacterPredicates.LETTERS.test('1')).isFalse();
-        assertThat(CharacterPredicates.LETTERS.test('?')).isFalse();
-        assertThat(CharacterPredicates.LETTERS.test('@')).isFalse();
+        assertThat(CharacterPredicates.ARABIC_NUMERALS.test('/')).isFalse();
+        assertThat(CharacterPredicates.ARABIC_NUMERALS.test(':')).isFalse();
+        assertThat(CharacterPredicates.ARABIC_NUMERALS.test('a')).isFalse();
     }
 
     @Test
-    public void testDigits() {
-        assertThat(CharacterPredicates.DIGITS.test('0')).isTrue();
-        assertThat(CharacterPredicates.DIGITS.test('9')).isTrue();
+    public void testAsciiAlphaNumerals() {
+        assertThat(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('a')).isTrue();
+        assertThat(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('z')).isTrue();
+        assertThat(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('A')).isTrue();
+        assertThat(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('Z')).isTrue();
+        assertThat(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('0')).isTrue();
+        assertThat(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('9')).isTrue();
 
-        assertThat(CharacterPredicates.DIGITS.test('-')).isFalse();
-        assertThat(CharacterPredicates.DIGITS.test('.')).isFalse();
-        assertThat(CharacterPredicates.DIGITS.test('L')).isFalse();
+        assertThat(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('`')).isFalse();
+        assertThat(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('{')).isFalse();
+        assertThat(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('@')).isFalse();
+        assertThat(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('[')).isFalse();
+        assertThat(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('/')).isFalse();
+        assertThat(CharacterPredicates.ASCII_ALPHA_NUMERALS.test(':')).isFalse();
     }
 
     @Test
-    public void testArabicNumerals() {
-        assertThat(CharacterPredicates.ARABIC_NUMERALS.test('0')).isTrue();
-        assertThat(CharacterPredicates.ARABIC_NUMERALS.test('1')).isTrue();
-        assertThat(CharacterPredicates.ARABIC_NUMERALS.test('9')).isTrue();
+    public void testAsciiLetters() {
+        assertThat(CharacterPredicates.ASCII_LETTERS.test('a')).isTrue();
+        assertThat(CharacterPredicates.ASCII_LETTERS.test('z')).isTrue();
+        assertThat(CharacterPredicates.ASCII_LETTERS.test('A')).isTrue();
+        assertThat(CharacterPredicates.ASCII_LETTERS.test('Z')).isTrue();
 
-        assertThat(CharacterPredicates.ARABIC_NUMERALS.test('/')).isFalse();
-        assertThat(CharacterPredicates.ARABIC_NUMERALS.test(':')).isFalse();
-        assertThat(CharacterPredicates.ARABIC_NUMERALS.test('a')).isFalse();
+        assertThat(CharacterPredicates.ASCII_LETTERS.test('9')).isFalse();
+        assertThat(CharacterPredicates.ASCII_LETTERS.test('`')).isFalse();
+        assertThat(CharacterPredicates.ASCII_LETTERS.test('{')).isFalse();
+        assertThat(CharacterPredicates.ASCII_LETTERS.test('@')).isFalse();
+        assertThat(CharacterPredicates.ASCII_LETTERS.test('[')).isFalse();
     }
 
     @Test
@@ -81,33 +92,22 @@ public class CharacterPredicatesTest {
     }
 
     @Test
-    public void testAsciiLetters() {
-        assertThat(CharacterPredicates.ASCII_LETTERS.test('a')).isTrue();
-        assertThat(CharacterPredicates.ASCII_LETTERS.test('z')).isTrue();
-        assertThat(CharacterPredicates.ASCII_LETTERS.test('A')).isTrue();
-        assertThat(CharacterPredicates.ASCII_LETTERS.test('Z')).isTrue();
+    public void testDigits() {
+        assertThat(CharacterPredicates.DIGITS.test('0')).isTrue();
+        assertThat(CharacterPredicates.DIGITS.test('9')).isTrue();
 
-        assertThat(CharacterPredicates.ASCII_LETTERS.test('9')).isFalse();
-        assertThat(CharacterPredicates.ASCII_LETTERS.test('`')).isFalse();
-        assertThat(CharacterPredicates.ASCII_LETTERS.test('{')).isFalse();
-        assertThat(CharacterPredicates.ASCII_LETTERS.test('@')).isFalse();
-        assertThat(CharacterPredicates.ASCII_LETTERS.test('[')).isFalse();
+        assertThat(CharacterPredicates.DIGITS.test('-')).isFalse();
+        assertThat(CharacterPredicates.DIGITS.test('.')).isFalse();
+        assertThat(CharacterPredicates.DIGITS.test('L')).isFalse();
     }
 
     @Test
-    public void testAsciiAlphaNumerals() {
-        assertThat(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('a')).isTrue();
-        assertThat(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('z')).isTrue();
-        assertThat(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('A')).isTrue();
-        assertThat(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('Z')).isTrue();
-        assertThat(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('0')).isTrue();
-        assertThat(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('9')).isTrue();
+    public void testLetters() {
+        assertThat(CharacterPredicates.LETTERS.test('a')).isTrue();
+        assertThat(CharacterPredicates.LETTERS.test('Z')).isTrue();
 
-        assertThat(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('`')).isFalse();
-        assertThat(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('{')).isFalse();
-        assertThat(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('@')).isFalse();
-        assertThat(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('[')).isFalse();
-        assertThat(CharacterPredicates.ASCII_ALPHA_NUMERALS.test('/')).isFalse();
-        assertThat(CharacterPredicates.ASCII_ALPHA_NUMERALS.test(':')).isFalse();
+        assertThat(CharacterPredicates.LETTERS.test('1')).isFalse();
+        assertThat(CharacterPredicates.LETTERS.test('?')).isFalse();
+        assertThat(CharacterPredicates.LETTERS.test('@')).isFalse();
     }
 }
diff --git a/src/test/java/org/apache/commons/text/ExtendedMessageFormatTest.java b/src/test/java/org/apache/commons/text/ExtendedMessageFormatTest.java
index 83d4fa1..bea150f 100644
--- a/src/test/java/org/apache/commons/text/ExtendedMessageFormatTest.java
+++ b/src/test/java/org/apache/commons/text/ExtendedMessageFormatTest.java
@@ -44,119 +44,116 @@ import org.junit.jupiter.api.Test;
  */
 public class ExtendedMessageFormatTest {
 
-    private final Map<String, FormatFactory> registry = new HashMap<>();
+    /**
+     * {@link Format} implementation which converts to lower case.
+     */
+    private static class LowerCaseFormat extends Format {
+        private static final long serialVersionUID = 1L;
 
-    @BeforeEach
-    public void setUp() {
-        registry.put("lower", new LowerCaseFormatFactory());
-        registry.put("upper", new UpperCaseFormatFactory());
+        @Override
+        public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) {
+            return toAppendTo.append(((String) obj).toLowerCase(Locale.ROOT));
+        }
+
+        @Override
+        public Object parseObject(final String source, final ParsePosition pos) {
+            throw new UnsupportedOperationException();
+        }
     }
 
+    // ------------------------ Test Format Factories ---------------
     /**
-     * Test extended formats.
+     * {@link FormatFactory} implementation for lower case format.
      */
-    @Test
-    public void testExtendedFormats() {
-        final String pattern = "Lower: {0,lower} Upper: {1,upper}";
-        final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
-        assertEquals(pattern, emf.toPattern(), "TOPATTERN");
-        assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"foo", "bar"}));
-        assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"Foo", "Bar"}));
-        assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"FOO", "BAR"}));
-        assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"FOO", "bar"}));
-        assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"foo", "BAR"}));
+    private static class LowerCaseFormatFactory implements FormatFactory {
+        private static final Format LOWER_INSTANCE = new LowerCaseFormat();
+        @Override
+        public Format getFormat(final String name, final String arguments, final Locale locale) {
+            return LOWER_INSTANCE;
+        }
     }
 
     /**
-     * Test Bug LANG-477 - out of memory error with escaped quote
+     * Alternative ExtendedMessageFormat impl.
      */
-    @Test
-    public void testEscapedQuote_LANG_477() {
-        final String pattern = "it''s a {0,lower} 'test'!";
-        final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
-        assertEquals("it's a dummy test!", emf.format(new Object[] {"DUMMY"}));
+    private static class OtherExtendedMessageFormat extends ExtendedMessageFormat {
+        private static final long serialVersionUID = 1L;
+
+        OtherExtendedMessageFormat(final String pattern, final Locale locale,
+                final Map<String, ? extends FormatFactory> registry) {
+            super(pattern, locale, registry);
+        }
     }
 
     /**
-     * Test Bug LANG-917 - IndexOutOfBoundsException and/or infinite loop when using a choice pattern
+     * {@link FormatFactory} implementation to override date format "short" to "default".
      */
-    @Test
-    public void testEmbeddedPatternInChoice() {
-        final String pattern = "Hi {0,lower}, got {1,choice,0#none|1#one|1<{1,number}}, {2,upper}!";
-        final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
-        assertEquals("Hi there, got 3, GREAT!", emf.format(new Object[] {"there", 3, "great"}));
+    private static class OverrideShortDateFormatFactory implements FormatFactory {
+        @Override
+        public Format getFormat(final String name, final String arguments, final Locale locale) {
+            return !"short".equals(arguments) ? null
+                    : locale == null ? DateFormat
+                            .getDateInstance(DateFormat.DEFAULT) : DateFormat
+                            .getDateInstance(DateFormat.DEFAULT, locale);
+        }
     }
 
     /**
-     * Test Bug LANG-948 - Exception while using ExtendedMessageFormat and escaping braces
+     * {@link Format} implementation which converts to upper case.
      */
-    @Test
-    public void testEscapedBraces_LANG_948() {
-        // message without placeholder because braces are escaped by quotes
-        final String pattern = "Message without placeholders '{}'";
-        final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
-        assertEquals("Message without placeholders {}", emf.format(new Object[] {"DUMMY"}));
+    private static class UpperCaseFormat extends Format {
+        private static final long serialVersionUID = 1L;
 
-        // message with placeholder because quotes are escaped by quotes
-        final String pattern2 = "Message with placeholder ''{0}''";
-        final ExtendedMessageFormat emf2 = new ExtendedMessageFormat(pattern2, registry);
-        assertEquals("Message with placeholder 'DUMMY'", emf2.format(new Object[] {"DUMMY"}));
+        @Override
+        public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) {
+            return toAppendTo.append(((String) obj).toUpperCase(Locale.ROOT));
+        }
+
+        @Override
+        public Object parseObject(final String source, final ParsePosition pos) {
+            throw new UnsupportedOperationException();
+        }
     }
 
     /**
-     * Test Bug TEXT-106 - Exception while using ExtendedMessageFormat and choice format element with quote just
-     * before brace end
+     * {@link FormatFactory} implementation for upper case format.
      */
-    @Test
-    public void testChoiceQuoteJustBeforeBraceEnd_TEXT_106() {
-        final String pattern2 = "Choice format element with quote just before brace end ''{0,choice,0#0|0<'1'}''";
-        final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern2, registry);
-        assertEquals("Choice format element with quote just before brace end '0'", emf.format(new Object[] {0}));
-        assertEquals("Choice format element with quote just before brace end '1'", emf.format(new Object[] {1}));
+    private static class UpperCaseFormatFactory implements FormatFactory {
+        private static final Format UPPER_INSTANCE = new UpperCaseFormat();
+        @Override
+        public Format getFormat(final String name, final String arguments, final Locale locale) {
+            return UPPER_INSTANCE;
+        }
     }
 
+    private final Map<String, FormatFactory> registry = new HashMap<>();
+
     /**
-     * Test extended and built in formats.
+     * Create an ExtendedMessageFormat for the specified pattern and locale and check the
+     * formated output matches the expected result for the parameters.
+     * @param pattern string
+     * @param registryUnused map (currently unused)
+     * @param args Object[]
+     * @param locale Locale
      */
-    @Test
-    public void testExtendedAndBuiltInFormats() {
-        final Calendar cal = Calendar.getInstance();
-        cal.set(2007, Calendar.JANUARY, 23, 18, 33, 5);
-        final Object[] args = new Object[] {"John Doe", cal.getTime(), Double.valueOf("12345.67")};
-        final String builtinsPattern = "DOB: {1,date,short} Salary: {2,number,currency}";
-        final String extendedPattern = "Name: {0,upper} ";
-        final String pattern = extendedPattern + builtinsPattern;
-
-        final HashSet<Locale> testLocales = new HashSet<>();
-        testLocales.addAll(Arrays.asList(DateFormat.getAvailableLocales()));
-        testLocales.retainAll(Arrays.asList(NumberFormat.getAvailableLocales()));
-        testLocales.add(null);
-
-        for (final Locale locale : testLocales) {
-            final MessageFormat builtins = createMessageFormat(builtinsPattern, locale);
-            final String expectedPattern = extendedPattern + builtins.toPattern();
-            DateFormat df = null;
-            NumberFormat nf = null;
-            ExtendedMessageFormat emf = null;
-            if (locale == null) {
-                df = DateFormat.getDateInstance(DateFormat.SHORT);
-                nf = NumberFormat.getCurrencyInstance();
-                emf = new ExtendedMessageFormat(pattern, registry);
-            } else {
-                df = DateFormat.getDateInstance(DateFormat.SHORT, locale);
-                nf = NumberFormat.getCurrencyInstance(locale);
-                emf = new ExtendedMessageFormat(pattern, locale, registry);
-            }
-            final StringBuilder expected = new StringBuilder();
-            expected.append("Name: ");
-            expected.append(args[0].toString().toUpperCase(Locale.ROOT));
-            expected.append(" DOB: ");
-            expected.append(df.format(args[1]));
-            expected.append(" Salary: ");
-            expected.append(nf.format(args[2]));
-            assertEquals(expectedPattern, emf.toPattern(), "pattern comparison for locale " + locale);
-            assertEquals(expected.toString(), emf.format(args), String.valueOf(locale));
+    private void checkBuiltInFormat(final String pattern, final Map<String, ?> registryUnused, final Object[] args,
+            final Locale locale) {
+        final StringBuilder buffer = new StringBuilder();
+        buffer.append("Pattern=[");
+        buffer.append(pattern);
+        buffer.append("], locale=[");
+        buffer.append(locale);
+        buffer.append("]");
+        final MessageFormat mf = createMessageFormat(pattern, locale);
+        // System.out.println(buffer + ", result=[" + mf.format(args) +"]");
+        ExtendedMessageFormat emf = null;
+        if (locale == null) {
+            emf = new ExtendedMessageFormat(pattern);
+        } else {
+            emf = new ExtendedMessageFormat(pattern, locale);
         }
+        assertEquals(mf.format(args), emf.format(args), "format "    + buffer.toString());
+        assertEquals(mf.toPattern(), emf.toPattern(), "toPattern " + buffer.toString());
     }
 
 //    /**
@@ -215,6 +212,52 @@ public class ExtendedMessageFormatTest {
 //    }
 
     /**
+     * Test a built in format for the specified Locales, plus {@code null} Locale.
+     * @param pattern MessageFormat pattern
+     * @param fmtRegistry FormatFactory registry to use
+     * @param args MessageFormat arguments
+     * @param locales to test
+     */
+    private void checkBuiltInFormat(final String pattern, final Map<String, ?> fmtRegistry, final Object[] args,
+            final Locale[] locales) {
+        checkBuiltInFormat(pattern, fmtRegistry, args, (Locale) null);
+        for (final Locale locale : locales) {
+            checkBuiltInFormat(pattern, fmtRegistry, args, locale);
+        }
+    }
+
+    /**
+     * Test a built in format for the specified Locales, plus {@code null} Locale.
+     * @param pattern MessageFormat pattern
+     * @param args MessageFormat arguments
+     * @param locales to test
+     */
+    private void checkBuiltInFormat(final String pattern, final Object[] args, final Locale[] locales) {
+        checkBuiltInFormat(pattern, null, args, locales);
+    }
+
+    /**
+     * Replace MessageFormat(String, Locale) constructor (not available until JDK 1.4).
+     * @param pattern string
+     * @param locale Locale
+     * @return MessageFormat
+     */
+    private MessageFormat createMessageFormat(final String pattern, final Locale locale) {
+        final MessageFormat result = new MessageFormat(pattern);
+        if (locale != null) {
+            result.setLocale(locale);
+            result.applyPattern(pattern);
+        }
+        return result;
+    }
+
+    @BeforeEach
+    public void setUp() {
+        registry.put("lower", new LowerCaseFormatFactory());
+        registry.put("upper", new UpperCaseFormatFactory());
+    }
+
+    /**
      * Test the built in choice format.
      */
     @Test
@@ -258,33 +301,6 @@ public class ExtendedMessageFormatTest {
         checkBuiltInFormat("12: {0,time}",         args, availableLocales);
     }
 
-    @Test
-    public void testOverriddenBuiltinFormat() {
-        final Calendar cal = Calendar.getInstance();
-        cal.set(2007, Calendar.JANUARY, 23);
-        final Object[] args = new Object[] {cal.getTime()};
-        final Locale[] availableLocales = DateFormat.getAvailableLocales();
-        final Map<String, ? extends FormatFactory> dateRegistry =
-                Collections.singletonMap("date", new OverrideShortDateFormatFactory());
-
-        //check the non-overridden builtins:
-        checkBuiltInFormat("1: {0,date}", dateRegistry,          args, availableLocales);
-        checkBuiltInFormat("2: {0,date,medium}", dateRegistry,   args, availableLocales);
-        checkBuiltInFormat("3: {0,date,long}", dateRegistry,     args, availableLocales);
-        checkBuiltInFormat("4: {0,date,full}", dateRegistry,     args, availableLocales);
-        checkBuiltInFormat("5: {0,date,d MMM yy}", dateRegistry, args, availableLocales);
-
-        //check the overridden format:
-        for (int i = -1; i < availableLocales.length; i++) {
-            final Locale locale = i < 0 ? null : availableLocales[i];
-            final MessageFormat dateDefault = createMessageFormat("{0,date}", locale);
-            final String pattern = "{0,date,short}";
-            final ExtendedMessageFormat dateShort = new ExtendedMessageFormat(pattern, locale, dateRegistry);
-            assertEquals(dateDefault.format(args), dateShort.format(args), "overridden date,short format");
-            assertEquals(pattern, dateShort.toPattern(), "overridden date,short pattern");
-        }
-    }
-
     /**
      * Test the built in number formats.
      */
@@ -300,14 +316,48 @@ public class ExtendedMessageFormatTest {
     }
 
     /**
-     * Test equals() and hashcode.
+     * Test Bug TEXT-106 - Exception while using ExtendedMessageFormat and choice format element with quote just
+     * before brace end
      */
     @Test
-    public void testEqualsHashcode() {
-        final Map<String, ? extends FormatFactory> fmtRegistry =
-                Collections.singletonMap("testfmt", new LowerCaseFormatFactory());
-        final Map<String, ? extends FormatFactory> otherRegitry =
-                Collections.singletonMap("testfmt", new UpperCaseFormatFactory());
+    public void testChoiceQuoteJustBeforeBraceEnd_TEXT_106() {
+        final String pattern2 = "Choice format element with quote just before brace end ''{0,choice,0#0|0<'1'}''";
+        final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern2, registry);
+        assertEquals("Choice format element with quote just before brace end '0'", emf.format(new Object[] {0}));
+        assertEquals("Choice format element with quote just before brace end '1'", emf.format(new Object[] {1}));
+    }
+
+    @Test
+    public void testCreatesExtendedMessageFormatTakingString() {
+        final ExtendedMessageFormat extendedMessageFormat =
+                new ExtendedMessageFormat("Unterminated format element at position ");
+        final Map<String, FormatFactory> map = new HashMap<>();
+        final ExtendedMessageFormat extendedMessageFormatTwo =
+                new ExtendedMessageFormat("Unterminated format element at position ", map);
+
+        assertEquals("Unterminated format element at position ", extendedMessageFormatTwo.toPattern());
+        assertFalse(extendedMessageFormat.equals(extendedMessageFormatTwo));
+    }
+
+    /**
+     * Test Bug LANG-917 - IndexOutOfBoundsException and/or infinite loop when using a choice pattern
+     */
+    @Test
+    public void testEmbeddedPatternInChoice() {
+        final String pattern = "Hi {0,lower}, got {1,choice,0#none|1#one|1<{1,number}}, {2,upper}!";
+        final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
+        assertEquals("Hi there, got 3, GREAT!", emf.format(new Object[] {"there", 3, "great"}));
+    }
+
+    /**
+     * Test equals() and hashcode.
+     */
+    @Test
+    public void testEqualsHashcode() {
+        final Map<String, ? extends FormatFactory> fmtRegistry =
+                Collections.singletonMap("testfmt", new LowerCaseFormatFactory());
+        final Map<String, ? extends FormatFactory> otherRegitry =
+                Collections.singletonMap("testfmt", new UpperCaseFormatFactory());
 
         final String pattern = "Pattern: {0,testfmt}";
         final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, Locale.US, fmtRegistry);
@@ -347,102 +397,101 @@ public class ExtendedMessageFormatTest {
     }
 
     /**
-     * Test a built in format for the specified Locales, plus {@code null} Locale.
-     * @param pattern MessageFormat pattern
-     * @param args MessageFormat arguments
-     * @param locales to test
+     * Test Bug LANG-948 - Exception while using ExtendedMessageFormat and escaping braces
      */
-    private void checkBuiltInFormat(final String pattern, final Object[] args, final Locale[] locales) {
-        checkBuiltInFormat(pattern, null, args, locales);
+    @Test
+    public void testEscapedBraces_LANG_948() {
+        // message without placeholder because braces are escaped by quotes
+        final String pattern = "Message without placeholders '{}'";
+        final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
+        assertEquals("Message without placeholders {}", emf.format(new Object[] {"DUMMY"}));
+
+        // message with placeholder because quotes are escaped by quotes
+        final String pattern2 = "Message with placeholder ''{0}''";
+        final ExtendedMessageFormat emf2 = new ExtendedMessageFormat(pattern2, registry);
+        assertEquals("Message with placeholder 'DUMMY'", emf2.format(new Object[] {"DUMMY"}));
     }
 
     /**
-     * Test a built in format for the specified Locales, plus {@code null} Locale.
-     * @param pattern MessageFormat pattern
-     * @param fmtRegistry FormatFactory registry to use
-     * @param args MessageFormat arguments
-     * @param locales to test
+     * Test Bug LANG-477 - out of memory error with escaped quote
      */
-    private void checkBuiltInFormat(final String pattern, final Map<String, ?> fmtRegistry, final Object[] args,
-            final Locale[] locales) {
-        checkBuiltInFormat(pattern, fmtRegistry, args, (Locale) null);
-        for (final Locale locale : locales) {
-            checkBuiltInFormat(pattern, fmtRegistry, args, locale);
-        }
+    @Test
+    public void testEscapedQuote_LANG_477() {
+        final String pattern = "it''s a {0,lower} 'test'!";
+        final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
+        assertEquals("it's a dummy test!", emf.format(new Object[] {"DUMMY"}));
     }
 
     /**
-     * Create an ExtendedMessageFormat for the specified pattern and locale and check the
-     * formated output matches the expected result for the parameters.
-     * @param pattern string
-     * @param registryUnused map (currently unused)
-     * @param args Object[]
-     * @param locale Locale
+     * Test extended and built in formats.
      */
-    private void checkBuiltInFormat(final String pattern, final Map<String, ?> registryUnused, final Object[] args,
-            final Locale locale) {
-        final StringBuilder buffer = new StringBuilder();
-        buffer.append("Pattern=[");
-        buffer.append(pattern);
-        buffer.append("], locale=[");
-        buffer.append(locale);
-        buffer.append("]");
-        final MessageFormat mf = createMessageFormat(pattern, locale);
-        // System.out.println(buffer + ", result=[" + mf.format(args) +"]");
-        ExtendedMessageFormat emf = null;
-        if (locale == null) {
-            emf = new ExtendedMessageFormat(pattern);
-        } else {
-            emf = new ExtendedMessageFormat(pattern, locale);
+    @Test
+    public void testExtendedAndBuiltInFormats() {
+        final Calendar cal = Calendar.getInstance();
+        cal.set(2007, Calendar.JANUARY, 23, 18, 33, 5);
+        final Object[] args = new Object[] {"John Doe", cal.getTime(), Double.valueOf("12345.67")};
+        final String builtinsPattern = "DOB: {1,date,short} Salary: {2,number,currency}";
+        final String extendedPattern = "Name: {0,upper} ";
+        final String pattern = extendedPattern + builtinsPattern;
+
+        final HashSet<Locale> testLocales = new HashSet<>();
+        testLocales.addAll(Arrays.asList(DateFormat.getAvailableLocales()));
+        testLocales.retainAll(Arrays.asList(NumberFormat.getAvailableLocales()));
+        testLocales.add(null);
+
+        for (final Locale locale : testLocales) {
+            final MessageFormat builtins = createMessageFormat(builtinsPattern, locale);
+            final String expectedPattern = extendedPattern + builtins.toPattern();
+            DateFormat df = null;
+            NumberFormat nf = null;
+            ExtendedMessageFormat emf = null;
+            if (locale == null) {
+                df = DateFormat.getDateInstance(DateFormat.SHORT);
+                nf = NumberFormat.getCurrencyInstance();
+                emf = new ExtendedMessageFormat(pattern, registry);
+            } else {
+                df = DateFormat.getDateInstance(DateFormat.SHORT, locale);
+                nf = NumberFormat.getCurrencyInstance(locale);
+                emf = new ExtendedMessageFormat(pattern, locale, registry);
+            }
+            final StringBuilder expected = new StringBuilder();
+            expected.append("Name: ");
+            expected.append(args[0].toString().toUpperCase(Locale.ROOT));
+            expected.append(" DOB: ");
+            expected.append(df.format(args[1]));
+            expected.append(" Salary: ");
+            expected.append(nf.format(args[2]));
+            assertEquals(expectedPattern, emf.toPattern(), "pattern comparison for locale " + locale);
+            assertEquals(expected.toString(), emf.format(args), String.valueOf(locale));
         }
-        assertEquals(mf.format(args), emf.format(args), "format "    + buffer.toString());
-        assertEquals(mf.toPattern(), emf.toPattern(), "toPattern " + buffer.toString());
     }
 
     /**
-     * Replace MessageFormat(String, Locale) constructor (not available until JDK 1.4).
-     * @param pattern string
-     * @param locale Locale
-     * @return MessageFormat
+     * Test extended formats.
      */
-    private MessageFormat createMessageFormat(final String pattern, final Locale locale) {
-        final MessageFormat result = new MessageFormat(pattern);
-        if (locale != null) {
-            result.setLocale(locale);
-            result.applyPattern(pattern);
-        }
-        return result;
-    }
-
-    @Test
-    public void testSetFormatIsUnsupported() {
-        assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> {
-            final ExtendedMessageFormat emf = new ExtendedMessageFormat("");
-            emf.setFormat(0, new LowerCaseFormat());
-        });
-    }
-
     @Test
-    public void testSetFormatByArgumentIndexIsUnsupported() {
-        assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> {
-            final ExtendedMessageFormat emf = new ExtendedMessageFormat("");
-            emf.setFormatByArgumentIndex(0, new LowerCaseFormat());
-        });
+    public void testExtendedFormats() {
+        final String pattern = "Lower: {0,lower} Upper: {1,upper}";
+        final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
+        assertEquals(pattern, emf.toPattern(), "TOPATTERN");
+        assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"foo", "bar"}));
+        assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"Foo", "Bar"}));
+        assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"FOO", "BAR"}));
+        assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"FOO", "bar"}));
+        assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"foo", "BAR"}));
     }
 
     @Test
-    public void testSetFormatsIsUnsupported() {
-        assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> {
-            final ExtendedMessageFormat emf = new ExtendedMessageFormat("");
-            emf.setFormats(new Format[] {new LowerCaseFormat(), new UpperCaseFormat()});
+    public void testFailsToCreateExtendedMessageFormatTakingTwoArgumentsThrowsIllegalArgumentExceptionFive() {
+        assertThatIllegalArgumentException().isThrownBy(() -> {
+            new ExtendedMessageFormat("j/[_D9{0,\"&'+0o", new HashMap<String, FormatFactory>());
         });
     }
 
     @Test
-    public void testSetFormatsByArgumentIndex() {
-        assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> {
-            final ExtendedMessageFormat emf = new ExtendedMessageFormat("");
-            emf.setFormatsByArgumentIndex(new Format[] {new LowerCaseFormat(), new UpperCaseFormat()});
+    public void testFailsToCreateExtendedMessageFormatTakingTwoArgumentsThrowsIllegalArgumentExceptionFour() {
+        assertThatIllegalArgumentException().isThrownBy(() -> {
+            new ExtendedMessageFormat("RD,nXhM{}{", new HashMap<String, FormatFactory>());
         });
     }
 
@@ -454,126 +503,77 @@ public class ExtendedMessageFormatTest {
     }
 
     @Test
-    public void testFailsToCreateExtendedMessageFormatTakingTwoArgumentsThrowsIllegalArgumentExceptionTwo() {
-        assertThatIllegalArgumentException().isThrownBy(() -> {
-            new ExtendedMessageFormat("a5XdkR;T1{9 ,LzXf?", new HashMap<String, FormatFactory>());
-        });
-    }
-
-    @Test
     public void testFailsToCreateExtendedMessageFormatTakingTwoArgumentsThrowsIllegalArgumentExceptionThree() {
         assertThatIllegalArgumentException().isThrownBy(() -> {
             new ExtendedMessageFormat("9jLh_D9{ ", new HashMap<String, FormatFactory>());
         });
     }
 
-    @Test
-    public void testFailsToCreateExtendedMessageFormatTakingTwoArgumentsThrowsIllegalArgumentExceptionFour() {
-        assertThatIllegalArgumentException().isThrownBy(() -> {
-            new ExtendedMessageFormat("RD,nXhM{}{", new HashMap<String, FormatFactory>());
-        });
-    }
+    // ------------------------ Test Formats ------------------------
 
     @Test
-    public void testFailsToCreateExtendedMessageFormatTakingTwoArgumentsThrowsIllegalArgumentExceptionFive() {
+    public void testFailsToCreateExtendedMessageFormatTakingTwoArgumentsThrowsIllegalArgumentExceptionTwo() {
         assertThatIllegalArgumentException().isThrownBy(() -> {
-            new ExtendedMessageFormat("j/[_D9{0,\"&'+0o", new HashMap<String, FormatFactory>());
+            new ExtendedMessageFormat("a5XdkR;T1{9 ,LzXf?", new HashMap<String, FormatFactory>());
         });
     }
 
     @Test
-    public void testCreatesExtendedMessageFormatTakingString() {
-        final ExtendedMessageFormat extendedMessageFormat =
-                new ExtendedMessageFormat("Unterminated format element at position ");
-        final Map<String, FormatFactory> map = new HashMap<>();
-        final ExtendedMessageFormat extendedMessageFormatTwo =
-                new ExtendedMessageFormat("Unterminated format element at position ", map);
-
-        assertEquals("Unterminated format element at position ", extendedMessageFormatTwo.toPattern());
-        assertFalse(extendedMessageFormat.equals(extendedMessageFormatTwo));
-    }
-
-    // ------------------------ Test Formats ------------------------
-
-    /**
-     * {@link Format} implementation which converts to lower case.
-     */
-    private static class LowerCaseFormat extends Format {
-        private static final long serialVersionUID = 1L;
-
-        @Override
-        public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) {
-            return toAppendTo.append(((String) obj).toLowerCase(Locale.ROOT));
-        }
-
-        @Override
-        public Object parseObject(final String source, final ParsePosition pos) {
-            throw new UnsupportedOperationException();
-        }
-    }
-
-    /**
-     * {@link Format} implementation which converts to upper case.
-     */
-    private static class UpperCaseFormat extends Format {
-        private static final long serialVersionUID = 1L;
+    public void testOverriddenBuiltinFormat() {
+        final Calendar cal = Calendar.getInstance();
+        cal.set(2007, Calendar.JANUARY, 23);
+        final Object[] args = new Object[] {cal.getTime()};
+        final Locale[] availableLocales = DateFormat.getAvailableLocales();
+        final Map<String, ? extends FormatFactory> dateRegistry =
+                Collections.singletonMap("date", new OverrideShortDateFormatFactory());
 
-        @Override
-        public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) {
-            return toAppendTo.append(((String) obj).toUpperCase(Locale.ROOT));
-        }
+        //check the non-overridden builtins:
+        checkBuiltInFormat("1: {0,date}", dateRegistry,          args, availableLocales);
+        checkBuiltInFormat("2: {0,date,medium}", dateRegistry,   args, availableLocales);
+        checkBuiltInFormat("3: {0,date,long}", dateRegistry,     args, availableLocales);
+        checkBuiltInFormat("4: {0,date,full}", dateRegistry,     args, availableLocales);
+        checkBuiltInFormat("5: {0,date,d MMM yy}", dateRegistry, args, availableLocales);
 
-        @Override
-        public Object parseObject(final String source, final ParsePosition pos) {
-            throw new UnsupportedOperationException();
+        //check the overridden format:
+        for (int i = -1; i < availableLocales.length; i++) {
+            final Locale locale = i < 0 ? null : availableLocales[i];
+            final MessageFormat dateDefault = createMessageFormat("{0,date}", locale);
+            final String pattern = "{0,date,short}";
+            final ExtendedMessageFormat dateShort = new ExtendedMessageFormat(pattern, locale, dateRegistry);
+            assertEquals(dateDefault.format(args), dateShort.format(args), "overridden date,short format");
+            assertEquals(pattern, dateShort.toPattern(), "overridden date,short pattern");
         }
     }
 
 
-    // ------------------------ Test Format Factories ---------------
-    /**
-     * {@link FormatFactory} implementation for lower case format.
-     */
-    private static class LowerCaseFormatFactory implements FormatFactory {
-        private static final Format LOWER_INSTANCE = new LowerCaseFormat();
-        @Override
-        public Format getFormat(final String name, final String arguments, final Locale locale) {
-            return LOWER_INSTANCE;
-        }
+    @Test
+    public void testSetFormatByArgumentIndexIsUnsupported() {
+        assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> {
+            final ExtendedMessageFormat emf = new ExtendedMessageFormat("");
+            emf.setFormatByArgumentIndex(0, new LowerCaseFormat());
+        });
     }
-    /**
-     * {@link FormatFactory} implementation for upper case format.
-     */
-    private static class UpperCaseFormatFactory implements FormatFactory {
-        private static final Format UPPER_INSTANCE = new UpperCaseFormat();
-        @Override
-        public Format getFormat(final String name, final String arguments, final Locale locale) {
-            return UPPER_INSTANCE;
-        }
+    @Test
+    public void testSetFormatIsUnsupported() {
+        assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> {
+            final ExtendedMessageFormat emf = new ExtendedMessageFormat("");
+            emf.setFormat(0, new LowerCaseFormat());
+        });
     }
-    /**
-     * {@link FormatFactory} implementation to override date format "short" to "default".
-     */
-    private static class OverrideShortDateFormatFactory implements FormatFactory {
-        @Override
-        public Format getFormat(final String name, final String arguments, final Locale locale) {
-            return !"short".equals(arguments) ? null
-                    : locale == null ? DateFormat
-                            .getDateInstance(DateFormat.DEFAULT) : DateFormat
-                            .getDateInstance(DateFormat.DEFAULT, locale);
-        }
+    @Test
+    public void testSetFormatsByArgumentIndex() {
+        assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> {
+            final ExtendedMessageFormat emf = new ExtendedMessageFormat("");
+            emf.setFormatsByArgumentIndex(new Format[] {new LowerCaseFormat(), new UpperCaseFormat()});
+        });
     }
 
-    /**
-     * Alternative ExtendedMessageFormat impl.
-     */
-    private static class OtherExtendedMessageFormat extends ExtendedMessageFormat {
-        private static final long serialVersionUID = 1L;
-
-        OtherExtendedMessageFormat(final String pattern, final Locale locale,
-                final Map<String, ? extends FormatFactory> registry) {
-            super(pattern, locale, registry);
-        }
+    @Test
+    public void testSetFormatsIsUnsupported() {
+        assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> {
+            final ExtendedMessageFormat emf = new ExtendedMessageFormat("");
+            emf.setFormats(new Format[] {new LowerCaseFormat(), new UpperCaseFormat()});
+        });
     }
 
 }
diff --git a/src/test/java/org/apache/commons/text/FormattableUtilsTest.java b/src/test/java/org/apache/commons/text/FormattableUtilsTest.java
index 6f5c2c3..2bcfdb8 100644
--- a/src/test/java/org/apache/commons/text/FormattableUtilsTest.java
+++ b/src/test/java/org/apache/commons/text/FormattableUtilsTest.java
@@ -31,20 +31,80 @@ import org.junit.jupiter.api.Test;
  */
 public class FormattableUtilsTest {
 
+    static class SimplestFormattable implements Formattable {
+        private final String text;
+
+        SimplestFormattable(final String text) {
+            this.text = text;
+        }
+
+        @Override
+        public void formatTo(final Formatter formatter, final int flags, final int width, final int precision) {
+            formatter.format(text);
+        }
+    }
+
     private Formatter createFormatter() {
         return new Formatter();
     }
 
     @Test
-    public void testPublicConstructorExists() {
-        new FormattableUtils();
+    public void testAlternatePadCharacter() {
+        final char pad = '_';
+        assertThat(FormattableUtils.append("foo", createFormatter(), 0, -1, -1, pad).toString()).isEqualTo("foo");
+        assertThat(FormattableUtils.append("foo", createFormatter(), 0, -1, 2, pad).toString()).isEqualTo("fo");
+        assertThat(FormattableUtils.append("foo", createFormatter(), 0, 4, -1, pad).toString()).isEqualTo("_foo");
+        assertThat(FormattableUtils.append("foo", createFormatter(), 0, 6, -1, pad).toString()).isEqualTo("___foo");
+        assertThat(FormattableUtils.append("foo", createFormatter(), 0, 3, 2, pad).toString()).isEqualTo("_fo");
+        assertThat(FormattableUtils.append("foo", createFormatter(), 0, 5, 2, pad).toString()).isEqualTo("___fo");
+        assertThat(FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 4, -1, pad).toString())
+            .isEqualTo("foo_");
+        assertThat(FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 6, -1, pad).toString())
+            .isEqualTo("foo___");
+        assertThat(FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 3, 2, pad).toString())
+            .isEqualTo("fo_");
+        assertThat(FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 5, 2, pad).toString())
+            .isEqualTo("fo___");
     }
 
     @Test
-    public void testSimplestFormat() {
-        final Formattable formattable = new SimplestFormattable("foo");
+    public void testAlternatePadCharAndEllipsis() {
+        assertThat(FormattableUtils.append("foo", createFormatter(), 0, -1, -1, '_', "*").toString()).isEqualTo("foo");
+        assertThat(FormattableUtils.append("foo", createFormatter(), 0, -1, 2, '_', "*").toString()).isEqualTo("f*");
+        assertThat(FormattableUtils.append("foo", createFormatter(), 0, 4, -1, '_', "*").toString()).isEqualTo("_foo");
+        assertThat(FormattableUtils.append("foo", createFormatter(), 0, 6, -1, '_', "*").toString())
+            .isEqualTo("___foo");
+        assertThat(FormattableUtils.append("foo", createFormatter(), 0, 3, 2, '_', "*").toString()).isEqualTo("_f*");
+        assertThat(FormattableUtils.append("foo", createFormatter(), 0, 5, 2, '_', "*").toString()).isEqualTo("___f*");
+        assertThat(FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 4, -1, '_', "*").toString())
+            .isEqualTo("foo_");
+        assertThat(FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 6, -1, '_', "*").toString())
+            .isEqualTo("foo___");
+        assertThat(FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 3, 2, '_', "*").toString())
+            .isEqualTo("f*_");
+        assertThat(FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 5, 2, '_', "*").toString())
+            .isEqualTo("f*___");
 
-        assertThat(FormattableUtils.toString(formattable)).isEqualTo("foo");
+        assertThat(FormattableUtils.append("foo", createFormatter(), 0, -1, -1, '_', "+*").toString()).isEqualTo("foo");
+        assertThat(FormattableUtils.append("foo", createFormatter(), 0, -1, 2, '_', "+*").toString()).isEqualTo("+*");
+        assertThat(FormattableUtils.append("foo", createFormatter(), 0, 4, -1, '_', "+*").toString()).isEqualTo("_foo");
+        assertThat(FormattableUtils.append("foo", createFormatter(), 0, 6, -1, '_', "+*").toString())
+            .isEqualTo("___foo");
+        assertThat(FormattableUtils.append("foo", createFormatter(), 0, 3, 2, '_', "+*").toString()).isEqualTo("_+*");
+        assertThat(FormattableUtils.append("foo", createFormatter(), 0, 5, 2, '_', "+*").toString()).isEqualTo("___+*");
+        assertThat(FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 4, -1, '_', "+*").toString())
+            .isEqualTo("foo_");
+        assertThat(FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 6, -1, '_', "+*").toString())
+            .isEqualTo("foo___");
+        assertThat(FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 3, 2, '_', "+*").toString())
+            .isEqualTo("+*_");
+        assertThat(FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 5, 2, '_', "+*").toString())
+            .isEqualTo("+*___");
+    }
+
+    @Test
+    public void testAppendWithNullFormatterAndIntsThrowsNullPointerException() {
+        assertThatNullPointerException().isThrownBy(() -> FormattableUtils.append("", null, 0, 0, 0, '}'));
     }
 
     @Test
@@ -63,25 +123,6 @@ public class FormattableUtilsTest {
     }
 
     @Test
-    public void testAlternatePadCharacter() {
-        final char pad = '_';
-        assertThat(FormattableUtils.append("foo", createFormatter(), 0, -1, -1, pad).toString()).isEqualTo("foo");
-        assertThat(FormattableUtils.append("foo", createFormatter(), 0, -1, 2, pad).toString()).isEqualTo("fo");
-        assertThat(FormattableUtils.append("foo", createFormatter(), 0, 4, -1, pad).toString()).isEqualTo("_foo");
-        assertThat(FormattableUtils.append("foo", createFormatter(), 0, 6, -1, pad).toString()).isEqualTo("___foo");
-        assertThat(FormattableUtils.append("foo", createFormatter(), 0, 3, 2, pad).toString()).isEqualTo("_fo");
-        assertThat(FormattableUtils.append("foo", createFormatter(), 0, 5, 2, pad).toString()).isEqualTo("___fo");
-        assertThat(FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 4, -1, pad).toString())
-            .isEqualTo("foo_");
-        assertThat(FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 6, -1, pad).toString())
-            .isEqualTo("foo___");
-        assertThat(FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 3, 2, pad).toString())
-            .isEqualTo("fo_");
-        assertThat(FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 5, 2, pad).toString())
-            .isEqualTo("fo___");
-    }
-
-    @Test
     public void testEllipsis() {
         assertThat(FormattableUtils.append("foo", createFormatter(), 0, -1, -1, "*").toString()).isEqualTo("foo");
         assertThat(FormattableUtils.append("foo", createFormatter(), 0, -1, 2, "*").toString()).isEqualTo("f*");
@@ -122,56 +163,15 @@ public class FormattableUtilsTest {
     }
 
     @Test
-    public void testAlternatePadCharAndEllipsis() {
-        assertThat(FormattableUtils.append("foo", createFormatter(), 0, -1, -1, '_', "*").toString()).isEqualTo("foo");
-        assertThat(FormattableUtils.append("foo", createFormatter(), 0, -1, 2, '_', "*").toString()).isEqualTo("f*");
-        assertThat(FormattableUtils.append("foo", createFormatter(), 0, 4, -1, '_', "*").toString()).isEqualTo("_foo");
-        assertThat(FormattableUtils.append("foo", createFormatter(), 0, 6, -1, '_', "*").toString())
-            .isEqualTo("___foo");
-        assertThat(FormattableUtils.append("foo", createFormatter(), 0, 3, 2, '_', "*").toString()).isEqualTo("_f*");
-        assertThat(FormattableUtils.append("foo", createFormatter(), 0, 5, 2, '_', "*").toString()).isEqualTo("___f*");
-        assertThat(FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 4, -1, '_', "*").toString())
-            .isEqualTo("foo_");
-        assertThat(FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 6, -1, '_', "*").toString())
-            .isEqualTo("foo___");
-        assertThat(FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 3, 2, '_', "*").toString())
-            .isEqualTo("f*_");
-        assertThat(FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 5, 2, '_', "*").toString())
-            .isEqualTo("f*___");
-
-        assertThat(FormattableUtils.append("foo", createFormatter(), 0, -1, -1, '_', "+*").toString()).isEqualTo("foo");
-        assertThat(FormattableUtils.append("foo", createFormatter(), 0, -1, 2, '_', "+*").toString()).isEqualTo("+*");
-        assertThat(FormattableUtils.append("foo", createFormatter(), 0, 4, -1, '_', "+*").toString()).isEqualTo("_foo");
-        assertThat(FormattableUtils.append("foo", createFormatter(), 0, 6, -1, '_', "+*").toString())
-            .isEqualTo("___foo");
-        assertThat(FormattableUtils.append("foo", createFormatter(), 0, 3, 2, '_', "+*").toString()).isEqualTo("_+*");
-        assertThat(FormattableUtils.append("foo", createFormatter(), 0, 5, 2, '_', "+*").toString()).isEqualTo("___+*");
-        assertThat(FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 4, -1, '_', "+*").toString())
-            .isEqualTo("foo_");
-        assertThat(FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 6, -1, '_', "+*").toString())
-            .isEqualTo("foo___");
-        assertThat(FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 3, 2, '_', "+*").toString())
-            .isEqualTo("+*_");
-        assertThat(FormattableUtils.append("foo", createFormatter(), LEFT_JUSTIFY, 5, 2, '_', "+*").toString())
-            .isEqualTo("+*___");
+    public void testPublicConstructorExists() {
+        new FormattableUtils();
     }
 
     @Test
-    public void testAppendWithNullFormatterAndIntsThrowsNullPointerException() {
-        assertThatNullPointerException().isThrownBy(() -> FormattableUtils.append("", null, 0, 0, 0, '}'));
-    }
-
-    static class SimplestFormattable implements Formattable {
-        private final String text;
-
-        SimplestFormattable(final String text) {
-            this.text = text;
-        }
+    public void testSimplestFormat() {
+        final Formattable formattable = new SimplestFormattable("foo");
 
-        @Override
-        public void formatTo(final Formatter formatter, final int flags, final int width, final int precision) {
-            formatter.format(text);
-        }
+        assertThat(FormattableUtils.toString(formattable)).isEqualTo("foo");
     }
 
 }
diff --git a/src/test/java/org/apache/commons/text/RandomStringGeneratorTest.java b/src/test/java/org/apache/commons/text/RandomStringGeneratorTest.java
index 2494694..3cffedf 100644
--- a/src/test/java/org/apache/commons/text/RandomStringGeneratorTest.java
+++ b/src/test/java/org/apache/commons/text/RandomStringGeneratorTest.java
@@ -32,40 +32,40 @@ public class RandomStringGeneratorTest {
 
     private static final CharacterPredicate B_FILTER = codePoint -> codePoint == 'b';
 
+    private static int codePointLength(final String s) {
+        return s.codePointCount(0, s.length());
+    }
+
     @Test
-    public void testInvalidLength() {
+    public void testBadMaximumCodePoint() {
         assertThatIllegalArgumentException().isThrownBy(() -> {
-            final RandomStringGenerator generator = new RandomStringGenerator.Builder().build();
-            generator.generate(-1);
+            new RandomStringGenerator.Builder().withinRange(0, Character.MAX_CODE_POINT + 1);
         });
     }
 
     @Test
-    public void testGenerateMinMaxLengthInvalidLength() {
+    public void testBadMinAndMax() {
         assertThatIllegalArgumentException().isThrownBy(() -> {
-            final RandomStringGenerator generator = new RandomStringGenerator.Builder().build();
-            generator.generate(-1, 0);
+            new RandomStringGenerator.Builder().withinRange(2, 1);
         });
     }
 
     @Test
-    public void testGenerateMinMaxLengthMinGreaterThanMax() {
+    public void testBadMinimumCodePoint() {
         assertThatIllegalArgumentException().isThrownBy(() -> {
-            final RandomStringGenerator generator = new RandomStringGenerator.Builder().build();
-            generator.generate(1, 0);
+            new RandomStringGenerator.Builder().withinRange(-1, 1);
         });
     }
 
-    private static int codePointLength(final String s) {
-        return s.codePointCount(0, s.length());
-    }
-
     @Test
-    public void testSetLength() {
-        final int length = 99;
-        final RandomStringGenerator generator = new RandomStringGenerator.Builder().build();
-        final String str = generator.generate(length);
-        assertThat(codePointLength(str)).isEqualTo(length);
+    public void testChangeOfFilter() {
+        final RandomStringGenerator.Builder builder = new RandomStringGenerator.Builder().withinRange('a', 'z')
+                .filteredBy(A_FILTER);
+        final String str = builder.filteredBy(B_FILTER).build().generate(100);
+
+        for (final char c : str.toCharArray()) {
+            assertThat(c == 'b').isTrue();
+        }
     }
 
     @Test
@@ -78,57 +78,60 @@ public class RandomStringGeneratorTest {
     }
 
     @Test
-    public void testBadMinimumCodePoint() {
+    public void testGenerateMinMaxLengthInvalidLength() {
         assertThatIllegalArgumentException().isThrownBy(() -> {
-            new RandomStringGenerator.Builder().withinRange(-1, 1);
+            final RandomStringGenerator generator = new RandomStringGenerator.Builder().build();
+            generator.generate(-1, 0);
         });
     }
 
     @Test
-    public void testBadMaximumCodePoint() {
+    public void testGenerateMinMaxLengthMinGreaterThanMax() {
         assertThatIllegalArgumentException().isThrownBy(() -> {
-            new RandomStringGenerator.Builder().withinRange(0, Character.MAX_CODE_POINT + 1);
+            final RandomStringGenerator generator = new RandomStringGenerator.Builder().build();
+            generator.generate(1, 0);
         });
     }
 
     @Test
-    public void testWithinRange() {
-        final int length = 5000;
-        final int minimumCodePoint = 'a';
-        final int maximumCodePoint = 'z';
-        final RandomStringGenerator generator = new RandomStringGenerator.Builder()
-                .withinRange(minimumCodePoint, maximumCodePoint).build();
-        final String str = generator.generate(length);
+    public void testGenerateTakingIntThrowsNullPointerException() {
+        assertThatNullPointerException().isThrownBy(() -> {
+            final RandomStringGenerator.Builder randomStringGeneratorBuilder = new RandomStringGenerator.Builder();
+            final CharacterPredicate[] characterPredicateArray = new CharacterPredicate[2];
+            randomStringGeneratorBuilder.filteredBy(characterPredicateArray);
+            final RandomStringGenerator randomStringGenerator = randomStringGeneratorBuilder.build();
 
-        int i = 0;
-        do {
-            final int codePoint = str.codePointAt(i);
-            assertThat(codePoint >= minimumCodePoint && codePoint <= maximumCodePoint).isTrue();
-            i += Character.charCount(codePoint);
-        } while (i < str.length());
+            randomStringGenerator.generate(18);
+        });
     }
 
     @Test
-    public void testWithinMultipleRanges() {
-        final int length = 5000;
-        final char[][] pairs = {{'a', 'z'}, {'0', '9'}};
-        final RandomStringGenerator generator = new RandomStringGenerator.Builder()
-                .withinRange(pairs).build();
-        final String str = generator.generate(length);
+    public void testInvalidLength() {
+        assertThatIllegalArgumentException().isThrownBy(() -> {
+            final RandomStringGenerator generator = new RandomStringGenerator.Builder().build();
+            generator.generate(-1);
+        });
+    }
 
-        int minimumCodePoint = 0, maximumCodePoint = 0;
+    @Test
+    public void testMultipleFilters() {
+        final String str = new RandomStringGenerator.Builder().withinRange('a', 'd')
+                .filteredBy(A_FILTER, B_FILTER).build().generate(5000);
 
-        for (final char[] pair : pairs) {
-            minimumCodePoint = Math.min(minimumCodePoint, pair[0]);
-            maximumCodePoint = Math.max(maximumCodePoint, pair[1]);
+        boolean aFound = false;
+        boolean bFound = false;
+
+        for (final char c : str.toCharArray()) {
+            if (c == 'a') {
+                aFound = true;
+            } else if (c == 'b') {
+                bFound = true;
+            } else {
+                fail("Invalid character");
+            }
         }
 
-        int i = 0;
-        do {
-            final int codePoint = str.codePointAt(i);
-            assertThat(codePoint >= minimumCodePoint && codePoint <= maximumCodePoint).isTrue();
-            i += Character.charCount(codePoint);
-        } while (i < str.length());
+        assertThat(aFound && bFound).isTrue();
     }
 
     @Test
@@ -158,38 +161,6 @@ public class RandomStringGeneratorTest {
     }
 
     @Test
-    public void testUsingRandom() {
-        final char testChar = 'a';
-        final TextRandomProvider testRandom = n -> testChar;
-
-        final String str = new RandomStringGenerator.Builder().usingRandom(testRandom).build().generate(10);
-        for (final char c : str.toCharArray()) {
-            assertThat(c).isEqualTo(testChar);
-        }
-    }
-
-    @Test
-    public void testMultipleFilters() {
-        final String str = new RandomStringGenerator.Builder().withinRange('a', 'd')
-                .filteredBy(A_FILTER, B_FILTER).build().generate(5000);
-
-        boolean aFound = false;
-        boolean bFound = false;
-
-        for (final char c : str.toCharArray()) {
-            if (c == 'a') {
-                aFound = true;
-            } else if (c == 'b') {
-                bFound = true;
-            } else {
-                fail("Invalid character");
-            }
-        }
-
-        assertThat(aFound && bFound).isTrue();
-    }
-
-    @Test
     public void testNoPrivateCharacters() {
         final int startOfPrivateBMPChars = 0xE000;
 
@@ -207,13 +178,6 @@ public class RandomStringGeneratorTest {
     }
 
     @Test
-    public void testBadMinAndMax() {
-        assertThatIllegalArgumentException().isThrownBy(() -> {
-            new RandomStringGenerator.Builder().withinRange(2, 1);
-        });
-    }
-
-    @Test
     public void testRemoveFilters() {
         final RandomStringGenerator.Builder builder = new RandomStringGenerator.Builder().withinRange('a', 'z')
                 .filteredBy(A_FILTER);
@@ -232,23 +196,6 @@ public class RandomStringGeneratorTest {
     }
 
     @Test
-    public void testChangeOfFilter() {
-        final RandomStringGenerator.Builder builder = new RandomStringGenerator.Builder().withinRange('a', 'z')
-                .filteredBy(A_FILTER);
-        final String str = builder.filteredBy(B_FILTER).build().generate(100);
-
-        for (final char c : str.toCharArray()) {
-            assertThat(c == 'b').isTrue();
-        }
-    }
-
-    @Test
-    public void testZeroLength() {
-        final RandomStringGenerator generator = new RandomStringGenerator.Builder().build();
-        assertThat(generator.generate(0)).isEqualTo("");
-    }
-
-    @Test
     public void testSelectFromCharArray() {
         final String str = "abc";
         final char[] charArray = str.toCharArray();
@@ -272,14 +219,67 @@ public class RandomStringGeneratorTest {
     }
 
     @Test
-    public void testGenerateTakingIntThrowsNullPointerException() {
-        assertThatNullPointerException().isThrownBy(() -> {
-            final RandomStringGenerator.Builder randomStringGeneratorBuilder = new RandomStringGenerator.Builder();
-            final CharacterPredicate[] characterPredicateArray = new CharacterPredicate[2];
-            randomStringGeneratorBuilder.filteredBy(characterPredicateArray);
-            final RandomStringGenerator randomStringGenerator = randomStringGeneratorBuilder.build();
+    public void testSetLength() {
+        final int length = 99;
+        final RandomStringGenerator generator = new RandomStringGenerator.Builder().build();
+        final String str = generator.generate(length);
+        assertThat(codePointLength(str)).isEqualTo(length);
+    }
 
-            randomStringGenerator.generate(18);
-        });
+    @Test
+    public void testUsingRandom() {
+        final char testChar = 'a';
+        final TextRandomProvider testRandom = n -> testChar;
+
+        final String str = new RandomStringGenerator.Builder().usingRandom(testRandom).build().generate(10);
+        for (final char c : str.toCharArray()) {
+            assertThat(c).isEqualTo(testChar);
+        }
+    }
+
+    @Test
+    public void testWithinMultipleRanges() {
+        final int length = 5000;
+        final char[][] pairs = {{'a', 'z'}, {'0', '9'}};
+        final RandomStringGenerator generator = new RandomStringGenerator.Builder()
+                .withinRange(pairs).build();
+        final String str = generator.generate(length);
+
+        int minimumCodePoint = 0, maximumCodePoint = 0;
+
+        for (final char[] pair : pairs) {
+            minimumCodePoint = Math.min(minimumCodePoint, pair[0]);
+            maximumCodePoint = Math.max(maximumCodePoint, pair[1]);
+        }
+
+        int i = 0;
+        do {
+            final int codePoint = str.codePointAt(i);
+            assertThat(codePoint >= minimumCodePoint && codePoint <= maximumCodePoint).isTrue();
+            i += Character.charCount(codePoint);
+        } while (i < str.length());
+    }
+
+    @Test
+    public void testWithinRange() {
+        final int length = 5000;
+        final int minimumCodePoint = 'a';
+        final int maximumCodePoint = 'z';
+        final RandomStringGenerator generator = new RandomStringGenerator.Builder()
+                .withinRange(minimumCodePoint, maximumCodePoint).build();
+        final String str = generator.generate(length);
+
+        int i = 0;
+        do {
+            final int codePoint = str.codePointAt(i);
+            assertThat(codePoint >= minimumCodePoint && codePoint <= maximumCodePoint).isTrue();
+            i += Character.charCount(codePoint);
+        } while (i < str.length());
+    }
+
+    @Test
+    public void testZeroLength() {
+        final RandomStringGenerator generator = new RandomStringGenerator.Builder().build();
+        assertThat(generator.generate(0)).isEqualTo("");
     }
 }
diff --git a/src/test/java/org/apache/commons/text/StrBuilderAppendInsertTest.java b/src/test/java/org/apache/commons/text/StrBuilderAppendInsertTest.java
index f916f25..6247936 100644
--- a/src/test/java/org/apache/commons/text/StrBuilderAppendInsertTest.java
+++ b/src/test/java/org/apache/commons/text/StrBuilderAppendInsertTest.java
@@ -51,46 +51,116 @@ public class StrBuilderAppendInsertTest {
 
     //-----------------------------------------------------------------------
     @Test
-    public void testAppendNewLine() {
-        StrBuilder sb = new StrBuilder("---");
-        sb.appendNewLine().append("+++");
-        assertThat(sb.toString()).isEqualTo("---" + SEP + "+++");
+    public void testAppend_Boolean() {
+        final StrBuilder sb = new StrBuilder();
+        sb.append(true);
+        assertThat(sb.toString()).isEqualTo("true");
 
-        sb = new StrBuilder("---");
-        sb.setNewLineText("#").appendNewLine().setNewLineText(null).appendNewLine();
-        assertThat(sb.toString()).isEqualTo("---#" + SEP);
+        sb.append(false);
+        assertThat(sb.toString()).isEqualTo("truefalse");
+
+        sb.append('!');
+        assertThat(sb.toString()).isEqualTo("truefalse!");
     }
 
     //-----------------------------------------------------------------------
     @Test
-    public void testAppendWithNullText() {
-        final StrBuilder sb = new StrBuilder();
-        sb.setNullText("NULL");
+    public void testAppend_CharArray() {
+        StrBuilder sb = new StrBuilder();
+        sb.setNullText("NULL").append((char[]) null);
+        assertThat(sb.toString()).isEqualTo("NULL");
+
+        sb = new StrBuilder();
+        sb.append(ArrayUtils.EMPTY_CHAR_ARRAY);
         assertThat(sb.toString()).isEqualTo("");
 
-        sb.appendNull();
+        sb.append(new char[]{'f', 'o', 'o'});
+        assertThat(sb.toString()).isEqualTo("foo");
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppend_CharArray_int_int() {
+        StrBuilder sb = new StrBuilder();
+        sb.setNullText("NULL").append((char[]) null, 0, 1);
         assertThat(sb.toString()).isEqualTo("NULL");
 
-        sb.append((Object) null);
-        assertThat(sb.toString()).isEqualTo("NULLNULL");
+        sb = new StrBuilder();
+        sb.append(new char[]{'f', 'o', 'o'}, 0, 3);
+        assertThat(sb.toString()).isEqualTo("foo");
 
-        sb.append(FOO);
-        assertThat(sb.toString()).isEqualTo("NULLNULLfoo");
+        try {
+            sb.append(new char[]{'b', 'a', 'r'}, -1, 1);
+            fail("append(char[], -1,) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
 
-        sb.append((String) null);
-        assertThat(sb.toString()).isEqualTo("NULLNULLfooNULL");
+        try {
+            sb.append(new char[]{'b', 'a', 'r'}, 3, 1);
+            fail("append(char[], 3,) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
 
-        sb.append("");
-        assertThat(sb.toString()).isEqualTo("NULLNULLfooNULL");
+        try {
+            sb.append(new char[]{'b', 'a', 'r'}, 1, -1);
+            fail("append(char[],, -1) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
 
-        sb.append("bar");
-        assertThat(sb.toString()).isEqualTo("NULLNULLfooNULLbar");
+        try {
+            sb.append(new char[]{'b', 'a', 'r'}, 1, 3);
+            fail("append(char[], 1, 3) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
 
-        sb.append((StringBuffer) null);
-        assertThat(sb.toString()).isEqualTo("NULLNULLfooNULLbarNULL");
+        try {
+            sb.append(new char[]{'b', 'a', 'r'}, -1, 3);
+            fail("append(char[], -1, 3) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
 
-        sb.append(new StringBuffer("baz"));
-        assertThat(sb.toString()).isEqualTo("NULLNULLfooNULLbarNULLbaz");
+        try {
+            sb.append(new char[]{'b', 'a', 'r'}, 4, 0);
+            fail("append(char[], 4, 0) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.append(new char[]{'b', 'a', 'r'}, 3, 0);
+        assertThat(sb.toString()).isEqualTo("foo");
+
+        sb.append(new char[]{'a', 'b', 'c', 'b', 'a', 'r', 'd', 'e', 'f'}, 3, 3);
+        assertThat(sb.toString()).isEqualTo("foobar");
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppend_FormattedString() {
+        StrBuilder sb;
+
+        sb = new StrBuilder();
+        sb.append("Hi", (Object[]) null);
+        assertThat(sb.toString()).isEqualTo("Hi");
+
+        sb = new StrBuilder();
+        sb.append("Hi", "Alice");
+        assertThat(sb.toString()).isEqualTo("Hi");
+
+        sb = new StrBuilder();
+        sb.append("Hi %s", "Alice");
+        assertThat(sb.toString()).isEqualTo("Hi Alice");
+
+        sb = new StrBuilder();
+        sb.append("Hi %s %,d", "Alice", 5000);
+        // group separator depends on system locale
+        final char groupingSeparator = DecimalFormatSymbols.getInstance().getGroupingSeparator();
+        final String expected = "Hi Alice 5" + groupingSeparator + "000";
+        assertThat(sb.toString()).isEqualTo(expected);
     }
 
     //-----------------------------------------------------------------------
@@ -124,163 +194,177 @@ public class StrBuilderAppendInsertTest {
 
     //-----------------------------------------------------------------------
     @Test
-    public void testAppend_StringBuilder() {
-        StrBuilder sb = new StrBuilder();
-        sb.setNullText("NULL").append((String) null);
-        assertThat(sb.toString()).isEqualTo("NULL");
+    public void testAppend_PrimitiveNumber() {
+        final StrBuilder sb = new StrBuilder();
+        sb.append(0);
+        assertThat(sb.toString()).isEqualTo("0");
 
-        sb = new StrBuilder();
-        sb.append(new StringBuilder("foo"));
-        assertThat(sb.toString()).isEqualTo("foo");
+        sb.append(1L);
+        assertThat(sb.toString()).isEqualTo("01");
 
-        sb.append(new StringBuilder(""));
-        assertThat(sb.toString()).isEqualTo("foo");
+        sb.append(2.3f);
+        assertThat(sb.toString()).isEqualTo("012.3");
 
-        sb.append(new StringBuilder("bar"));
-        assertThat(sb.toString()).isEqualTo("foobar");
+        sb.append(4.5d);
+        assertThat(sb.toString()).isEqualTo("012.34.5");
     }
 
     //-----------------------------------------------------------------------
     @Test
-    public void testAppend_String() {
+    public void testAppend_StrBuilder() {
         StrBuilder sb = new StrBuilder();
-        sb.setNullText("NULL").append((String) null);
+        sb.setNullText("NULL").append((StrBuilder) null);
         assertThat(sb.toString()).isEqualTo("NULL");
 
         sb = new StrBuilder();
-        sb.append("foo");
+        sb.append(new StrBuilder("foo"));
         assertThat(sb.toString()).isEqualTo("foo");
 
-        sb.append("");
+        sb.append(new StrBuilder(""));
         assertThat(sb.toString()).isEqualTo("foo");
 
-        sb.append("bar");
+        sb.append(new StrBuilder("bar"));
         assertThat(sb.toString()).isEqualTo("foobar");
     }
 
     //-----------------------------------------------------------------------
     @Test
-    public void testAppend_String_int_int() {
+    public void testAppend_StrBuilder_int_int() {
         StrBuilder sb = new StrBuilder();
-        sb.setNullText("NULL").append((String) null, 0, 1);
+        sb.setNullText("NULL").append((StrBuilder) null, 0, 1);
         assertThat(sb.toString()).isEqualTo("NULL");
 
         sb = new StrBuilder();
-        sb.append("foo", 0, 3);
+        sb.append(new StrBuilder("foo"), 0, 3);
         assertThat(sb.toString()).isEqualTo("foo");
 
         try {
-            sb.append("bar", -1, 1);
+            sb.append(new StrBuilder("bar"), -1, 1);
             fail("append(char[], -1,) expected IndexOutOfBoundsException");
         } catch (final IndexOutOfBoundsException e) {
             // expected
         }
 
         try {
-            sb.append("bar", 3, 1);
+            sb.append(new StrBuilder("bar"), 3, 1);
             fail("append(char[], 3,) expected IndexOutOfBoundsException");
         } catch (final IndexOutOfBoundsException e) {
             // expected
         }
 
         try {
-            sb.append("bar", 1, -1);
+            sb.append(new StrBuilder("bar"), 1, -1);
             fail("append(char[],, -1) expected IndexOutOfBoundsException");
         } catch (final IndexOutOfBoundsException e) {
             // expected
         }
 
         try {
-            sb.append("bar", 1, 3);
+            sb.append(new StrBuilder("bar"), 1, 3);
             fail("append(char[], 1, 3) expected IndexOutOfBoundsException");
         } catch (final IndexOutOfBoundsException e) {
             // expected
         }
 
         try {
-            sb.append("bar", -1, 3);
+            sb.append(new StrBuilder("bar"), -1, 3);
             fail("append(char[], -1, 3) expected IndexOutOfBoundsException");
         } catch (final IndexOutOfBoundsException e) {
             // expected
         }
 
         try {
-            sb.append("bar", 4, 0);
+            sb.append(new StrBuilder("bar"), 4, 0);
             fail("append(char[], 4, 0) expected IndexOutOfBoundsException");
         } catch (final IndexOutOfBoundsException e) {
             // expected
         }
 
-        sb.append("bar", 3, 0);
+        sb.append(new StrBuilder("bar"), 3, 0);
         assertThat(sb.toString()).isEqualTo("foo");
 
-        sb.append("abcbardef", 3, 3);
+        sb.append(new StrBuilder("abcbardef"), 3, 3);
         assertThat(sb.toString()).isEqualTo("foobar");
+    }
 
-        sb.append((CharSequence) "abcbardef", 4, 3);
-        assertThat(sb.toString()).isEqualTo("foobarard");
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppend_String() {
+        StrBuilder sb = new StrBuilder();
+        sb.setNullText("NULL").append((String) null);
+        assertThat(sb.toString()).isEqualTo("NULL");
+
+        sb = new StrBuilder();
+        sb.append("foo");
+        assertThat(sb.toString()).isEqualTo("foo");
+
+        sb.append("");
+        assertThat(sb.toString()).isEqualTo("foo");
+
+        sb.append("bar");
+        assertThat(sb.toString()).isEqualTo("foobar");
     }
 
     //-----------------------------------------------------------------------
     @Test
-    public void testAppend_StringBuilder_int_int() {
+    public void testAppend_String_int_int() {
         StrBuilder sb = new StrBuilder();
         sb.setNullText("NULL").append((String) null, 0, 1);
         assertThat(sb.toString()).isEqualTo("NULL");
 
         sb = new StrBuilder();
-        sb.append(new StringBuilder("foo"), 0, 3);
+        sb.append("foo", 0, 3);
         assertThat(sb.toString()).isEqualTo("foo");
 
         try {
-            sb.append(new StringBuilder("bar"), -1, 1);
-            fail("append(StringBuilder, -1,) expected IndexOutOfBoundsException");
+            sb.append("bar", -1, 1);
+            fail("append(char[], -1,) expected IndexOutOfBoundsException");
         } catch (final IndexOutOfBoundsException e) {
             // expected
         }
 
         try {
-            sb.append(new StringBuilder("bar"), 3, 1);
-            fail("append(StringBuilder, 3,) expected IndexOutOfBoundsException");
+            sb.append("bar", 3, 1);
+            fail("append(char[], 3,) expected IndexOutOfBoundsException");
         } catch (final IndexOutOfBoundsException e) {
             // expected
         }
 
         try {
-            sb.append(new StringBuilder("bar"), 1, -1);
-            fail("append(StringBuilder,, -1) expected IndexOutOfBoundsException");
+            sb.append("bar", 1, -1);
+            fail("append(char[],, -1) expected IndexOutOfBoundsException");
         } catch (final IndexOutOfBoundsException e) {
             // expected
         }
 
         try {
-            sb.append(new StringBuilder("bar"), 1, 3);
-            fail("append(StringBuilder, 1, 3) expected IndexOutOfBoundsException");
+            sb.append("bar", 1, 3);
+            fail("append(char[], 1, 3) expected IndexOutOfBoundsException");
         } catch (final IndexOutOfBoundsException e) {
             // expected
         }
 
         try {
-            sb.append(new StringBuilder("bar"), -1, 3);
-            fail("append(StringBuilder, -1, 3) expected IndexOutOfBoundsException");
+            sb.append("bar", -1, 3);
+            fail("append(char[], -1, 3) expected IndexOutOfBoundsException");
         } catch (final IndexOutOfBoundsException e) {
             // expected
         }
 
         try {
-            sb.append(new StringBuilder("bar"), 4, 0);
-            fail("append(StringBuilder, 4, 0) expected IndexOutOfBoundsException");
+            sb.append("bar", 4, 0);
+            fail("append(char[], 4, 0) expected IndexOutOfBoundsException");
         } catch (final IndexOutOfBoundsException e) {
             // expected
         }
 
-        sb.append(new StringBuilder("bar"), 3, 0);
+        sb.append("bar", 3, 0);
         assertThat(sb.toString()).isEqualTo("foo");
 
-        sb.append(new StringBuilder("abcbardef"), 3, 3);
+        sb.append("abcbardef", 3, 3);
         assertThat(sb.toString()).isEqualTo("foobar");
 
-        sb.append(new StringBuilder("abcbardef"), 4, 3);
+        sb.append((CharSequence) "abcbardef", 4, 3);
         assertThat(sb.toString()).isEqualTo("foobarard");
     }
 
@@ -364,197 +448,304 @@ public class StrBuilderAppendInsertTest {
 
     //-----------------------------------------------------------------------
     @Test
-    public void testAppend_StrBuilder() {
+    public void testAppend_StringBuilder() {
         StrBuilder sb = new StrBuilder();
-        sb.setNullText("NULL").append((StrBuilder) null);
+        sb.setNullText("NULL").append((String) null);
         assertThat(sb.toString()).isEqualTo("NULL");
 
         sb = new StrBuilder();
-        sb.append(new StrBuilder("foo"));
+        sb.append(new StringBuilder("foo"));
         assertThat(sb.toString()).isEqualTo("foo");
 
-        sb.append(new StrBuilder(""));
+        sb.append(new StringBuilder(""));
         assertThat(sb.toString()).isEqualTo("foo");
 
-        sb.append(new StrBuilder("bar"));
+        sb.append(new StringBuilder("bar"));
         assertThat(sb.toString()).isEqualTo("foobar");
     }
 
     //-----------------------------------------------------------------------
     @Test
-    public void testAppend_StrBuilder_int_int() {
+    public void testAppend_StringBuilder_int_int() {
         StrBuilder sb = new StrBuilder();
-        sb.setNullText("NULL").append((StrBuilder) null, 0, 1);
+        sb.setNullText("NULL").append((String) null, 0, 1);
         assertThat(sb.toString()).isEqualTo("NULL");
 
         sb = new StrBuilder();
-        sb.append(new StrBuilder("foo"), 0, 3);
+        sb.append(new StringBuilder("foo"), 0, 3);
         assertThat(sb.toString()).isEqualTo("foo");
 
         try {
-            sb.append(new StrBuilder("bar"), -1, 1);
-            fail("append(char[], -1,) expected IndexOutOfBoundsException");
+            sb.append(new StringBuilder("bar"), -1, 1);
+            fail("append(StringBuilder, -1,) expected IndexOutOfBoundsException");
         } catch (final IndexOutOfBoundsException e) {
             // expected
         }
 
         try {
-            sb.append(new StrBuilder("bar"), 3, 1);
-            fail("append(char[], 3,) expected IndexOutOfBoundsException");
+            sb.append(new StringBuilder("bar"), 3, 1);
+            fail("append(StringBuilder, 3,) expected IndexOutOfBoundsException");
         } catch (final IndexOutOfBoundsException e) {
             // expected
         }
 
         try {
-            sb.append(new StrBuilder("bar"), 1, -1);
-            fail("append(char[],, -1) expected IndexOutOfBoundsException");
+            sb.append(new StringBuilder("bar"), 1, -1);
+            fail("append(StringBuilder,, -1) expected IndexOutOfBoundsException");
         } catch (final IndexOutOfBoundsException e) {
             // expected
         }
 
         try {
-            sb.append(new StrBuilder("bar"), 1, 3);
-            fail("append(char[], 1, 3) expected IndexOutOfBoundsException");
+            sb.append(new StringBuilder("bar"), 1, 3);
+            fail("append(StringBuilder, 1, 3) expected IndexOutOfBoundsException");
         } catch (final IndexOutOfBoundsException e) {
             // expected
         }
 
         try {
-            sb.append(new StrBuilder("bar"), -1, 3);
-            fail("append(char[], -1, 3) expected IndexOutOfBoundsException");
+            sb.append(new StringBuilder("bar"), -1, 3);
+            fail("append(StringBuilder, -1, 3) expected IndexOutOfBoundsException");
         } catch (final IndexOutOfBoundsException e) {
             // expected
         }
 
         try {
-            sb.append(new StrBuilder("bar"), 4, 0);
-            fail("append(char[], 4, 0) expected IndexOutOfBoundsException");
+            sb.append(new StringBuilder("bar"), 4, 0);
+            fail("append(StringBuilder, 4, 0) expected IndexOutOfBoundsException");
         } catch (final IndexOutOfBoundsException e) {
             // expected
         }
 
-        sb.append(new StrBuilder("bar"), 3, 0);
+        sb.append(new StringBuilder("bar"), 3, 0);
         assertThat(sb.toString()).isEqualTo("foo");
 
-        sb.append(new StrBuilder("abcbardef"), 3, 3);
+        sb.append(new StringBuilder("abcbardef"), 3, 3);
         assertThat(sb.toString()).isEqualTo("foobar");
+
+        sb.append(new StringBuilder("abcbardef"), 4, 3);
+        assertThat(sb.toString()).isEqualTo("foobarard");
     }
 
     //-----------------------------------------------------------------------
     @Test
-    public void testAppend_CharArray() {
-        StrBuilder sb = new StrBuilder();
-        sb.setNullText("NULL").append((char[]) null);
-        assertThat(sb.toString()).isEqualTo("NULL");
+    public void testAppendAll_Array() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendAll((Object[]) null);
+        assertThat(sb.toString()).isEqualTo("");
 
-        sb = new StrBuilder();
-        sb.append(ArrayUtils.EMPTY_CHAR_ARRAY);
+        sb.clear();
+        sb.appendAll();
         assertThat(sb.toString()).isEqualTo("");
 
-        sb.append(new char[]{'f', 'o', 'o'});
-        assertThat(sb.toString()).isEqualTo("foo");
+        sb.clear();
+        sb.appendAll("foo", "bar", "baz");
+        assertThat(sb.toString()).isEqualTo("foobarbaz");
+
+        sb.clear();
+        sb.appendAll("foo", "bar", "baz");
+        assertThat(sb.toString()).isEqualTo("foobarbaz");
     }
 
     //-----------------------------------------------------------------------
     @Test
-    public void testAppend_CharArray_int_int() {
-        StrBuilder sb = new StrBuilder();
-        sb.setNullText("NULL").append((char[]) null, 0, 1);
-        assertThat(sb.toString()).isEqualTo("NULL");
+    public void testAppendAll_Collection() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendAll((Collection<?>) null);
+        assertThat(sb.toString()).isEqualTo("");
 
-        sb = new StrBuilder();
-        sb.append(new char[]{'f', 'o', 'o'}, 0, 3);
-        assertThat(sb.toString()).isEqualTo("foo");
+        sb.clear();
+        sb.appendAll(Collections.EMPTY_LIST);
+        assertThat(sb.toString()).isEqualTo("");
 
-        try {
-            sb.append(new char[]{'b', 'a', 'r'}, -1, 1);
-            fail("append(char[], -1,) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
+        sb.clear();
+        sb.appendAll(Arrays.asList("foo", "bar", "baz"));
+        assertThat(sb.toString()).isEqualTo("foobarbaz");
+    }
 
-        try {
-            sb.append(new char[]{'b', 'a', 'r'}, 3, 1);
-            fail("append(char[], 3,) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendAll_Iterator() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendAll((Iterator<?>) null);
+        assertThat(sb.toString()).isEqualTo("");
 
-        try {
-            sb.append(new char[]{'b', 'a', 'r'}, 1, -1);
-            fail("append(char[],, -1) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
+        sb.clear();
+        sb.appendAll(Collections.EMPTY_LIST.iterator());
+        assertThat(sb.toString()).isEqualTo("");
 
-        try {
-            sb.append(new char[]{'b', 'a', 'r'}, 1, 3);
-            fail("append(char[], 1, 3) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
+        sb.clear();
+        sb.appendAll(Arrays.asList("foo", "bar", "baz").iterator());
+        assertThat(sb.toString()).isEqualTo("foobarbaz");
+    }
 
-        try {
-            sb.append(new char[]{'b', 'a', 'r'}, -1, 3);
-            fail("append(char[], -1, 3) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendFixedWidthPadLeft() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendFixedWidthPadLeft("foo", -1, '-');
+        assertThat(sb.toString()).isEqualTo("");
 
-        try {
-            sb.append(new char[]{'b', 'a', 'r'}, 4, 0);
-            fail("append(char[], 4, 0) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
+        sb.clear();
+        sb.appendFixedWidthPadLeft("foo", 0, '-');
+        assertThat(sb.toString()).isEqualTo("");
 
-        sb.append(new char[]{'b', 'a', 'r'}, 3, 0);
+        sb.clear();
+        sb.appendFixedWidthPadLeft("foo", 1, '-');
+        assertThat(sb.toString()).isEqualTo("o");
+
+        sb.clear();
+        sb.appendFixedWidthPadLeft("foo", 2, '-');
+        assertThat(sb.toString()).isEqualTo("oo");
+
+        sb.clear();
+        sb.appendFixedWidthPadLeft("foo", 3, '-');
         assertThat(sb.toString()).isEqualTo("foo");
 
-        sb.append(new char[]{'a', 'b', 'c', 'b', 'a', 'r', 'd', 'e', 'f'}, 3, 3);
-        assertThat(sb.toString()).isEqualTo("foobar");
+        sb.clear();
+        sb.appendFixedWidthPadLeft("foo", 4, '-');
+        assertThat(sb.toString()).isEqualTo("-foo");
+
+        sb.clear();
+        sb.appendFixedWidthPadLeft("foo", 10, '-');
+        assertThat(sb.length()).isEqualTo(10);
+        //            1234567890
+        assertThat(sb.toString()).isEqualTo("-------foo");
+
+        sb.clear();
+        sb.setNullText("null");
+        sb.appendFixedWidthPadLeft(null, 5, '-');
+        assertThat(sb.toString()).isEqualTo("-null");
     }
 
     //-----------------------------------------------------------------------
     @Test
-    public void testAppend_Boolean() {
+    public void testAppendFixedWidthPadLeft_int() {
         final StrBuilder sb = new StrBuilder();
-        sb.append(true);
-        assertThat(sb.toString()).isEqualTo("true");
+        sb.appendFixedWidthPadLeft(123, -1, '-');
+        assertThat(sb.toString()).isEqualTo("");
 
-        sb.append(false);
-        assertThat(sb.toString()).isEqualTo("truefalse");
+        sb.clear();
+        sb.appendFixedWidthPadLeft(123, 0, '-');
+        assertThat(sb.toString()).isEqualTo("");
 
-        sb.append('!');
-        assertThat(sb.toString()).isEqualTo("truefalse!");
+        sb.clear();
+        sb.appendFixedWidthPadLeft(123, 1, '-');
+        assertThat(sb.toString()).isEqualTo("3");
+
+        sb.clear();
+        sb.appendFixedWidthPadLeft(123, 2, '-');
+        assertThat(sb.toString()).isEqualTo("23");
+
+        sb.clear();
+        sb.appendFixedWidthPadLeft(123, 3, '-');
+        assertThat(sb.toString()).isEqualTo("123");
+
+        sb.clear();
+        sb.appendFixedWidthPadLeft(123, 4, '-');
+        assertThat(sb.toString()).isEqualTo("-123");
+
+        sb.clear();
+        sb.appendFixedWidthPadLeft(123, 10, '-');
+        assertThat(sb.length()).isEqualTo(10);
+        //            1234567890
+        assertThat(sb.toString()).isEqualTo("-------123");
     }
 
     //-----------------------------------------------------------------------
     @Test
-    public void testAppend_PrimitiveNumber() {
+    public void testAppendFixedWidthPadRight() {
         final StrBuilder sb = new StrBuilder();
-        sb.append(0);
-        assertThat(sb.toString()).isEqualTo("0");
+        sb.appendFixedWidthPadRight("foo", -1, '-');
+        assertThat(sb.toString()).isEqualTo("");
 
-        sb.append(1L);
-        assertThat(sb.toString()).isEqualTo("01");
+        sb.clear();
+        sb.appendFixedWidthPadRight("foo", 0, '-');
+        assertThat(sb.toString()).isEqualTo("");
 
-        sb.append(2.3f);
-        assertThat(sb.toString()).isEqualTo("012.3");
+        sb.clear();
+        sb.appendFixedWidthPadRight("foo", 1, '-');
+        assertThat(sb.toString()).isEqualTo("f");
 
-        sb.append(4.5d);
-        assertThat(sb.toString()).isEqualTo("012.34.5");
+        sb.clear();
+        sb.appendFixedWidthPadRight("foo", 2, '-');
+        assertThat(sb.toString()).isEqualTo("fo");
+
+        sb.clear();
+        sb.appendFixedWidthPadRight("foo", 3, '-');
+        assertThat(sb.toString()).isEqualTo("foo");
+
+        sb.clear();
+        sb.appendFixedWidthPadRight("foo", 4, '-');
+        assertThat(sb.toString()).isEqualTo("foo-");
+
+        sb.clear();
+        sb.appendFixedWidthPadRight("foo", 10, '-');
+        assertThat(sb.length()).isEqualTo(10);
+        //            1234567890
+        assertThat(sb.toString()).isEqualTo("foo-------");
+
+        sb.clear();
+        sb.setNullText("null");
+        sb.appendFixedWidthPadRight(null, 5, '-');
+        assertThat(sb.toString()).isEqualTo("null-");
     }
 
     //-----------------------------------------------------------------------
     @Test
-    public void testAppendln_FormattedString() {
+    public void testAppendFixedWidthPadRight_int() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendFixedWidthPadRight(123, -1, '-');
+        assertThat(sb.toString()).isEqualTo("");
+
+        sb.clear();
+        sb.appendFixedWidthPadRight(123, 0, '-');
+        assertThat(sb.toString()).isEqualTo("");
+
+        sb.clear();
+        sb.appendFixedWidthPadRight(123, 1, '-');
+        assertThat(sb.toString()).isEqualTo("1");
+
+        sb.clear();
+        sb.appendFixedWidthPadRight(123, 2, '-');
+        assertThat(sb.toString()).isEqualTo("12");
+
+        sb.clear();
+        sb.appendFixedWidthPadRight(123, 3, '-');
+        assertThat(sb.toString()).isEqualTo("123");
+
+        sb.clear();
+        sb.appendFixedWidthPadRight(123, 4, '-');
+        assertThat(sb.toString()).isEqualTo("123-");
+
+        sb.clear();
+        sb.appendFixedWidthPadRight(123, 10, '-');
+        assertThat(sb.length()).isEqualTo(10);
+        //            1234567890
+        assertThat(sb.toString()).isEqualTo("123-------");
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendln_Boolean() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendln(true);
+        assertThat(sb.toString()).isEqualTo("true" + SEP);
+
+        sb.clear();
+        sb.appendln(false);
+        assertThat(sb.toString()).isEqualTo("false" + SEP);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendln_CharArray() {
         final int[] count = new int[2];
         final StrBuilder sb = new StrBuilder() {
             private static final long serialVersionUID = 1L;
 
             @Override
-            public StrBuilder append(final String str) {
+            public StrBuilder append(final char[] str) {
                 count[0]++;
                 return super.append(str);
             }
@@ -564,37 +755,23 @@ public class StrBuilderAppendInsertTest {
                 return super.appendNewLine();
             }
         };
-        sb.appendln("Hello %s", "Alice");
-        assertThat(sb.toString()).isEqualTo("Hello Alice" + SEP);
-        assertThat(count[0]).isEqualTo(2); // appendNewLine() calls append(String)
+        sb.appendln("foo".toCharArray());
+        assertThat(sb.toString()).isEqualTo("foo" + SEP);
+        assertThat(count[0]).isEqualTo(1);
         assertThat(count[1]).isEqualTo(1);
     }
 
     //-----------------------------------------------------------------------
     @Test
-    public void testAppendln_Object() {
-        final StrBuilder sb = new StrBuilder();
-        sb.appendln((Object) null);
-        assertThat(sb.toString()).isEqualTo("" + SEP);
-
-        sb.appendln(FOO);
-        assertThat(sb.toString()).isEqualTo(SEP + "foo" + SEP);
-
-        sb.appendln(Integer.valueOf(6));
-        assertThat(sb.toString()).isEqualTo(SEP + "foo" + SEP + "6" + SEP);
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendln_String() {
+    public void testAppendln_CharArray_int_int() {
         final int[] count = new int[2];
         final StrBuilder sb = new StrBuilder() {
             private static final long serialVersionUID = 1L;
 
             @Override
-            public StrBuilder append(final String str) {
+            public StrBuilder append(final char[] str, final int startIndex, final int length) {
                 count[0]++;
-                return super.append(str);
+                return super.append(str, startIndex, length);
             }
             @Override
             public StrBuilder appendNewLine() {
@@ -602,23 +779,23 @@ public class StrBuilderAppendInsertTest {
                 return super.appendNewLine();
             }
         };
-        sb.appendln("foo");
+        sb.appendln("foo".toCharArray(), 0, 3);
         assertThat(sb.toString()).isEqualTo("foo" + SEP);
-        assertThat(count[0]).isEqualTo(2); // appendNewLine() calls append(String)
+        assertThat(count[0]).isEqualTo(1);
         assertThat(count[1]).isEqualTo(1);
     }
 
     //-----------------------------------------------------------------------
     @Test
-    public void testAppendln_String_int_int() {
+    public void testAppendln_FormattedString() {
         final int[] count = new int[2];
         final StrBuilder sb = new StrBuilder() {
             private static final long serialVersionUID = 1L;
 
             @Override
-            public StrBuilder append(final String str, final int startIndex, final int length) {
+            public StrBuilder append(final String str) {
                 count[0]++;
-                return super.append(str, startIndex, length);
+                return super.append(str);
             }
             @Override
             public StrBuilder appendNewLine() {
@@ -626,21 +803,55 @@ public class StrBuilderAppendInsertTest {
                 return super.appendNewLine();
             }
         };
-        sb.appendln("foo", 0, 3);
-        assertThat(sb.toString()).isEqualTo("foo" + SEP);
-        assertThat(count[0]).isEqualTo(1);
+        sb.appendln("Hello %s", "Alice");
+        assertThat(sb.toString()).isEqualTo("Hello Alice" + SEP);
+        assertThat(count[0]).isEqualTo(2); // appendNewLine() calls append(String)
         assertThat(count[1]).isEqualTo(1);
     }
 
     //-----------------------------------------------------------------------
     @Test
-    public void testAppendln_StringBuffer() {
+    public void testAppendln_Object() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendln((Object) null);
+        assertThat(sb.toString()).isEqualTo("" + SEP);
+
+        sb.appendln(FOO);
+        assertThat(sb.toString()).isEqualTo(SEP + "foo" + SEP);
+
+        sb.appendln(Integer.valueOf(6));
+        assertThat(sb.toString()).isEqualTo(SEP + "foo" + SEP + "6" + SEP);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendln_PrimitiveNumber() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendln(0);
+        assertThat(sb.toString()).isEqualTo("0" + SEP);
+
+        sb.clear();
+        sb.appendln(1L);
+        assertThat(sb.toString()).isEqualTo("1" + SEP);
+
+        sb.clear();
+        sb.appendln(2.3f);
+        assertThat(sb.toString()).isEqualTo("2.3" + SEP);
+
+        sb.clear();
+        sb.appendln(4.5d);
+        assertThat(sb.toString()).isEqualTo("4.5" + SEP);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendln_StrBuilder() {
         final int[] count = new int[2];
         final StrBuilder sb = new StrBuilder() {
             private static final long serialVersionUID = 1L;
 
             @Override
-            public StrBuilder append(final StringBuffer str) {
+            public StrBuilder append(final StrBuilder str) {
                 count[0]++;
                 return super.append(str);
             }
@@ -650,7 +861,7 @@ public class StrBuilderAppendInsertTest {
                 return super.appendNewLine();
             }
         };
-        sb.appendln(new StringBuffer("foo"));
+        sb.appendln(new StrBuilder("foo"));
         assertThat(sb.toString()).isEqualTo("foo" + SEP);
         assertThat(count[0]).isEqualTo(1);
         assertThat(count[1]).isEqualTo(1);
@@ -658,15 +869,15 @@ public class StrBuilderAppendInsertTest {
 
     //-----------------------------------------------------------------------
     @Test
-    public void testAppendln_StringBuilder() {
+    public void testAppendln_StrBuilder_int_int() {
         final int[] count = new int[2];
         final StrBuilder sb = new StrBuilder() {
             private static final long serialVersionUID = 1L;
 
             @Override
-            public StrBuilder append(final StringBuilder str) {
+            public StrBuilder append(final StrBuilder str, final int startIndex, final int length) {
                 count[0]++;
-                return super.append(str);
+                return super.append(str, startIndex, length);
             }
             @Override
             public StrBuilder appendNewLine() {
@@ -674,7 +885,7 @@ public class StrBuilderAppendInsertTest {
                 return super.appendNewLine();
             }
         };
-        sb.appendln(new StringBuilder("foo"));
+        sb.appendln(new StrBuilder("foo"), 0, 3);
         assertThat(sb.toString()).isEqualTo("foo" + SEP);
         assertThat(count[0]).isEqualTo(1);
         assertThat(count[1]).isEqualTo(1);
@@ -682,15 +893,15 @@ public class StrBuilderAppendInsertTest {
 
     //-----------------------------------------------------------------------
     @Test
-    public void testAppendln_StringBuffer_int_int() {
+    public void testAppendln_String() {
         final int[] count = new int[2];
         final StrBuilder sb = new StrBuilder() {
             private static final long serialVersionUID = 1L;
 
             @Override
-            public StrBuilder append(final StringBuffer str, final int startIndex, final int length) {
+            public StrBuilder append(final String str) {
                 count[0]++;
-                return super.append(str, startIndex, length);
+                return super.append(str);
             }
             @Override
             public StrBuilder appendNewLine() {
@@ -698,21 +909,21 @@ public class StrBuilderAppendInsertTest {
                 return super.appendNewLine();
             }
         };
-        sb.appendln(new StringBuffer("foo"), 0, 3);
+        sb.appendln("foo");
         assertThat(sb.toString()).isEqualTo("foo" + SEP);
-        assertThat(count[0]).isEqualTo(1);
+        assertThat(count[0]).isEqualTo(2); // appendNewLine() calls append(String)
         assertThat(count[1]).isEqualTo(1);
     }
 
     //-----------------------------------------------------------------------
     @Test
-    public void testAppendln_StringBuilder_int_int() {
+    public void testAppendln_String_int_int() {
         final int[] count = new int[2];
         final StrBuilder sb = new StrBuilder() {
             private static final long serialVersionUID = 1L;
 
             @Override
-            public StrBuilder append(final StringBuilder str, final int startIndex, final int length) {
+            public StrBuilder append(final String str, final int startIndex, final int length) {
                 count[0]++;
                 return super.append(str, startIndex, length);
             }
@@ -722,7 +933,7 @@ public class StrBuilderAppendInsertTest {
                 return super.appendNewLine();
             }
         };
-        sb.appendln(new StringBuilder("foo"), 0, 3);
+        sb.appendln("foo", 0, 3);
         assertThat(sb.toString()).isEqualTo("foo" + SEP);
         assertThat(count[0]).isEqualTo(1);
         assertThat(count[1]).isEqualTo(1);
@@ -730,13 +941,13 @@ public class StrBuilderAppendInsertTest {
 
     //-----------------------------------------------------------------------
     @Test
-    public void testAppendln_StrBuilder() {
+    public void testAppendln_StringBuffer() {
         final int[] count = new int[2];
         final StrBuilder sb = new StrBuilder() {
             private static final long serialVersionUID = 1L;
 
             @Override
-            public StrBuilder append(final StrBuilder str) {
+            public StrBuilder append(final StringBuffer str) {
                 count[0]++;
                 return super.append(str);
             }
@@ -746,7 +957,7 @@ public class StrBuilderAppendInsertTest {
                 return super.appendNewLine();
             }
         };
-        sb.appendln(new StrBuilder("foo"));
+        sb.appendln(new StringBuffer("foo"));
         assertThat(sb.toString()).isEqualTo("foo" + SEP);
         assertThat(count[0]).isEqualTo(1);
         assertThat(count[1]).isEqualTo(1);
@@ -754,13 +965,13 @@ public class StrBuilderAppendInsertTest {
 
     //-----------------------------------------------------------------------
     @Test
-    public void testAppendln_StrBuilder_int_int() {
+    public void testAppendln_StringBuffer_int_int() {
         final int[] count = new int[2];
         final StrBuilder sb = new StrBuilder() {
             private static final long serialVersionUID = 1L;
 
             @Override
-            public StrBuilder append(final StrBuilder str, final int startIndex, final int length) {
+            public StrBuilder append(final StringBuffer str, final int startIndex, final int length) {
                 count[0]++;
                 return super.append(str, startIndex, length);
             }
@@ -770,7 +981,7 @@ public class StrBuilderAppendInsertTest {
                 return super.appendNewLine();
             }
         };
-        sb.appendln(new StrBuilder("foo"), 0, 3);
+        sb.appendln(new StringBuffer("foo"), 0, 3);
         assertThat(sb.toString()).isEqualTo("foo" + SEP);
         assertThat(count[0]).isEqualTo(1);
         assertThat(count[1]).isEqualTo(1);
@@ -778,13 +989,13 @@ public class StrBuilderAppendInsertTest {
 
     //-----------------------------------------------------------------------
     @Test
-    public void testAppendln_CharArray() {
+    public void testAppendln_StringBuilder() {
         final int[] count = new int[2];
         final StrBuilder sb = new StrBuilder() {
             private static final long serialVersionUID = 1L;
 
             @Override
-            public StrBuilder append(final char[] str) {
+            public StrBuilder append(final StringBuilder str) {
                 count[0]++;
                 return super.append(str);
             }
@@ -794,7 +1005,7 @@ public class StrBuilderAppendInsertTest {
                 return super.appendNewLine();
             }
         };
-        sb.appendln("foo".toCharArray());
+        sb.appendln(new StringBuilder("foo"));
         assertThat(sb.toString()).isEqualTo("foo" + SEP);
         assertThat(count[0]).isEqualTo(1);
         assertThat(count[1]).isEqualTo(1);
@@ -802,13 +1013,13 @@ public class StrBuilderAppendInsertTest {
 
     //-----------------------------------------------------------------------
     @Test
-    public void testAppendln_CharArray_int_int() {
+    public void testAppendln_StringBuilder_int_int() {
         final int[] count = new int[2];
         final StrBuilder sb = new StrBuilder() {
             private static final long serialVersionUID = 1L;
 
             @Override
-            public StrBuilder append(final char[] str, final int startIndex, final int length) {
+            public StrBuilder append(final StringBuilder str, final int startIndex, final int length) {
                 count[0]++;
                 return super.append(str, startIndex, length);
             }
@@ -818,7 +1029,7 @@ public class StrBuilderAppendInsertTest {
                 return super.appendNewLine();
             }
         };
-        sb.appendln("foo".toCharArray(), 0, 3);
+        sb.appendln(new StringBuilder("foo"), 0, 3);
         assertThat(sb.toString()).isEqualTo("foo" + SEP);
         assertThat(count[0]).isEqualTo(1);
         assertThat(count[1]).isEqualTo(1);
@@ -826,287 +1037,159 @@ public class StrBuilderAppendInsertTest {
 
     //-----------------------------------------------------------------------
     @Test
-    public void testAppendln_Boolean() {
-        final StrBuilder sb = new StrBuilder();
-        sb.appendln(true);
-        assertThat(sb.toString()).isEqualTo("true" + SEP);
-
-        sb.clear();
-        sb.appendln(false);
-        assertThat(sb.toString()).isEqualTo("false" + SEP);
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendln_PrimitiveNumber() {
-        final StrBuilder sb = new StrBuilder();
-        sb.appendln(0);
-        assertThat(sb.toString()).isEqualTo("0" + SEP);
-
-        sb.clear();
-        sb.appendln(1L);
-        assertThat(sb.toString()).isEqualTo("1" + SEP);
-
-        sb.clear();
-        sb.appendln(2.3f);
-        assertThat(sb.toString()).isEqualTo("2.3" + SEP);
-
-        sb.clear();
-        sb.appendln(4.5d);
-        assertThat(sb.toString()).isEqualTo("4.5" + SEP);
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendPadding() {
-        final StrBuilder sb = new StrBuilder();
-        sb.append("foo");
-        assertThat(sb.toString()).isEqualTo("foo");
-
-        sb.appendPadding(-1, '-');
-        assertThat(sb.toString()).isEqualTo("foo");
-
-        sb.appendPadding(0, '-');
-        assertThat(sb.toString()).isEqualTo("foo");
-
-        sb.appendPadding(1, '-');
-        assertThat(sb.toString()).isEqualTo("foo-");
-
-        sb.appendPadding(16, '-');
-        assertThat(sb.length()).isEqualTo(20);
-        //            12345678901234567890
-        assertThat(sb.toString()).isEqualTo("foo-----------------");
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendFixedWidthPadLeft() {
-        final StrBuilder sb = new StrBuilder();
-        sb.appendFixedWidthPadLeft("foo", -1, '-');
-        assertThat(sb.toString()).isEqualTo("");
-
-        sb.clear();
-        sb.appendFixedWidthPadLeft("foo", 0, '-');
-        assertThat(sb.toString()).isEqualTo("");
-
-        sb.clear();
-        sb.appendFixedWidthPadLeft("foo", 1, '-');
-        assertThat(sb.toString()).isEqualTo("o");
-
-        sb.clear();
-        sb.appendFixedWidthPadLeft("foo", 2, '-');
-        assertThat(sb.toString()).isEqualTo("oo");
-
-        sb.clear();
-        sb.appendFixedWidthPadLeft("foo", 3, '-');
-        assertThat(sb.toString()).isEqualTo("foo");
-
-        sb.clear();
-        sb.appendFixedWidthPadLeft("foo", 4, '-');
-        assertThat(sb.toString()).isEqualTo("-foo");
-
-        sb.clear();
-        sb.appendFixedWidthPadLeft("foo", 10, '-');
-        assertThat(sb.length()).isEqualTo(10);
-        //            1234567890
-        assertThat(sb.toString()).isEqualTo("-------foo");
-
-        sb.clear();
-        sb.setNullText("null");
-        sb.appendFixedWidthPadLeft(null, 5, '-');
-        assertThat(sb.toString()).isEqualTo("-null");
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendFixedWidthPadLeft_int() {
-        final StrBuilder sb = new StrBuilder();
-        sb.appendFixedWidthPadLeft(123, -1, '-');
-        assertThat(sb.toString()).isEqualTo("");
-
-        sb.clear();
-        sb.appendFixedWidthPadLeft(123, 0, '-');
-        assertThat(sb.toString()).isEqualTo("");
-
-        sb.clear();
-        sb.appendFixedWidthPadLeft(123, 1, '-');
-        assertThat(sb.toString()).isEqualTo("3");
-
-        sb.clear();
-        sb.appendFixedWidthPadLeft(123, 2, '-');
-        assertThat(sb.toString()).isEqualTo("23");
-
-        sb.clear();
-        sb.appendFixedWidthPadLeft(123, 3, '-');
-        assertThat(sb.toString()).isEqualTo("123");
-
-        sb.clear();
-        sb.appendFixedWidthPadLeft(123, 4, '-');
-        assertThat(sb.toString()).isEqualTo("-123");
-
-        sb.clear();
-        sb.appendFixedWidthPadLeft(123, 10, '-');
-        assertThat(sb.length()).isEqualTo(10);
-        //            1234567890
-        assertThat(sb.toString()).isEqualTo("-------123");
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendFixedWidthPadRight() {
-        final StrBuilder sb = new StrBuilder();
-        sb.appendFixedWidthPadRight("foo", -1, '-');
-        assertThat(sb.toString()).isEqualTo("");
-
-        sb.clear();
-        sb.appendFixedWidthPadRight("foo", 0, '-');
-        assertThat(sb.toString()).isEqualTo("");
-
-        sb.clear();
-        sb.appendFixedWidthPadRight("foo", 1, '-');
-        assertThat(sb.toString()).isEqualTo("f");
-
-        sb.clear();
-        sb.appendFixedWidthPadRight("foo", 2, '-');
-        assertThat(sb.toString()).isEqualTo("fo");
-
-        sb.clear();
-        sb.appendFixedWidthPadRight("foo", 3, '-');
-        assertThat(sb.toString()).isEqualTo("foo");
-
-        sb.clear();
-        sb.appendFixedWidthPadRight("foo", 4, '-');
-        assertThat(sb.toString()).isEqualTo("foo-");
-
-        sb.clear();
-        sb.appendFixedWidthPadRight("foo", 10, '-');
-        assertThat(sb.length()).isEqualTo(10);
-        //            1234567890
-        assertThat(sb.toString()).isEqualTo("foo-------");
-
-        sb.clear();
-        sb.setNullText("null");
-        sb.appendFixedWidthPadRight(null, 5, '-');
-        assertThat(sb.toString()).isEqualTo("null-");
-    }
-
-    // See: https://issues.apache.org/jira/browse/LANG-299
-    @Test
-    public void testLang299() {
-        final StrBuilder sb = new StrBuilder(1);
-        sb.appendFixedWidthPadRight("foo", 1, '-');
-        assertThat(sb.toString()).isEqualTo("f");
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendFixedWidthPadRight_int() {
-        final StrBuilder sb = new StrBuilder();
-        sb.appendFixedWidthPadRight(123, -1, '-');
-        assertThat(sb.toString()).isEqualTo("");
-
-        sb.clear();
-        sb.appendFixedWidthPadRight(123, 0, '-');
-        assertThat(sb.toString()).isEqualTo("");
-
-        sb.clear();
-        sb.appendFixedWidthPadRight(123, 1, '-');
-        assertThat(sb.toString()).isEqualTo("1");
-
-        sb.clear();
-        sb.appendFixedWidthPadRight(123, 2, '-');
-        assertThat(sb.toString()).isEqualTo("12");
-
-        sb.clear();
-        sb.appendFixedWidthPadRight(123, 3, '-');
-        assertThat(sb.toString()).isEqualTo("123");
-
-        sb.clear();
-        sb.appendFixedWidthPadRight(123, 4, '-');
-        assertThat(sb.toString()).isEqualTo("123-");
-
-        sb.clear();
-        sb.appendFixedWidthPadRight(123, 10, '-');
-        assertThat(sb.length()).isEqualTo(10);
-        //            1234567890
-        assertThat(sb.toString()).isEqualTo("123-------");
+    public void testAppendNewLine() {
+        StrBuilder sb = new StrBuilder("---");
+        sb.appendNewLine().append("+++");
+        assertThat(sb.toString()).isEqualTo("---" + SEP + "+++");
+
+        sb = new StrBuilder("---");
+        sb.setNewLineText("#").appendNewLine().setNewLineText(null).appendNewLine();
+        assertThat(sb.toString()).isEqualTo("---#" + SEP);
     }
 
     //-----------------------------------------------------------------------
     @Test
-    public void testAppend_FormattedString() {
-        StrBuilder sb;
+    public void testAppendPadding() {
+        final StrBuilder sb = new StrBuilder();
+        sb.append("foo");
+        assertThat(sb.toString()).isEqualTo("foo");
 
-        sb = new StrBuilder();
-        sb.append("Hi", (Object[]) null);
-        assertThat(sb.toString()).isEqualTo("Hi");
+        sb.appendPadding(-1, '-');
+        assertThat(sb.toString()).isEqualTo("foo");
 
-        sb = new StrBuilder();
-        sb.append("Hi", "Alice");
-        assertThat(sb.toString()).isEqualTo("Hi");
+        sb.appendPadding(0, '-');
+        assertThat(sb.toString()).isEqualTo("foo");
 
-        sb = new StrBuilder();
-        sb.append("Hi %s", "Alice");
-        assertThat(sb.toString()).isEqualTo("Hi Alice");
+        sb.appendPadding(1, '-');
+        assertThat(sb.toString()).isEqualTo("foo-");
 
-        sb = new StrBuilder();
-        sb.append("Hi %s %,d", "Alice", 5000);
-        // group separator depends on system locale
-        final char groupingSeparator = DecimalFormatSymbols.getInstance().getGroupingSeparator();
-        final String expected = "Hi Alice 5" + groupingSeparator + "000";
-        assertThat(sb.toString()).isEqualTo(expected);
+        sb.appendPadding(16, '-');
+        assertThat(sb.length()).isEqualTo(20);
+        //            12345678901234567890
+        assertThat(sb.toString()).isEqualTo("foo-----------------");
     }
 
     //-----------------------------------------------------------------------
     @Test
-    public void testAppendAll_Array() {
+    public void testAppendSeparator_char() {
         final StrBuilder sb = new StrBuilder();
-        sb.appendAll((Object[]) null);
+        sb.appendSeparator(',');  // no effect
         assertThat(sb.toString()).isEqualTo("");
+        sb.append("foo");
+        assertThat(sb.toString()).isEqualTo("foo");
+        sb.appendSeparator(',');
+        assertThat(sb.toString()).isEqualTo("foo,");
+    }
 
-        sb.clear();
-        sb.appendAll();
-        assertThat(sb.toString()).isEqualTo("");
+    @Test
+    public void testAppendSeparator_char_char() {
+        final StrBuilder sb = new StrBuilder();
+        final char startSeparator = ':';
+        final char standardSeparator = ',';
+        final String foo = "foo";
+        sb.appendSeparator(standardSeparator, startSeparator);  // no effect
+        assertThat(sb.toString()).isEqualTo(String.valueOf(startSeparator));
+        sb.append(foo);
+        assertThat(sb.toString()).isEqualTo(String.valueOf(startSeparator) + foo);
+        sb.appendSeparator(standardSeparator, startSeparator);
+        assertThat(sb.toString()).isEqualTo(String.valueOf(startSeparator) + foo + standardSeparator);
+    }
 
-        sb.clear();
-        sb.appendAll("foo", "bar", "baz");
-        assertThat(sb.toString()).isEqualTo("foobarbaz");
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendSeparator_char_int() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendSeparator(',', 0);  // no effect
+        assertThat(sb.toString()).isEqualTo("");
+        sb.append("foo");
+        assertThat(sb.toString()).isEqualTo("foo");
+        sb.appendSeparator(',', 1);
+        assertThat(sb.toString()).isEqualTo("foo,");
 
-        sb.clear();
-        sb.appendAll("foo", "bar", "baz");
-        assertThat(sb.toString()).isEqualTo("foobarbaz");
+        sb.appendSeparator(',', -1);  // no effect
+        assertThat(sb.toString()).isEqualTo("foo,");
     }
 
     //-----------------------------------------------------------------------
     @Test
-    public void testAppendAll_Collection() {
+    public void testAppendSeparator_String() {
         final StrBuilder sb = new StrBuilder();
-        sb.appendAll((Collection<?>) null);
+        sb.appendSeparator(",");  // no effect
         assertThat(sb.toString()).isEqualTo("");
+        sb.append("foo");
+        assertThat(sb.toString()).isEqualTo("foo");
+        sb.appendSeparator(",");
+        assertThat(sb.toString()).isEqualTo("foo,");
+    }
 
-        sb.clear();
-        sb.appendAll(Collections.EMPTY_LIST);
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendSeparator_String_int() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendSeparator(",", 0);  // no effect
         assertThat(sb.toString()).isEqualTo("");
+        sb.append("foo");
+        assertThat(sb.toString()).isEqualTo("foo");
+        sb.appendSeparator(",", 1);
+        assertThat(sb.toString()).isEqualTo("foo,");
 
-        sb.clear();
-        sb.appendAll(Arrays.asList("foo", "bar", "baz"));
-        assertThat(sb.toString()).isEqualTo("foobarbaz");
+        sb.appendSeparator(",", -1);  // no effect
+        assertThat(sb.toString()).isEqualTo("foo,");
     }
 
     //-----------------------------------------------------------------------
     @Test
-    public void testAppendAll_Iterator() {
+    public void testAppendSeparator_String_String() {
         final StrBuilder sb = new StrBuilder();
-        sb.appendAll((Iterator<?>) null);
+        final String startSeparator = "order by ";
+        final String standardSeparator = ",";
+        final String foo = "foo";
+        sb.appendSeparator(null, null);
+        assertThat(sb.toString()).isEqualTo("");
+        sb.appendSeparator(standardSeparator, null);
         assertThat(sb.toString()).isEqualTo("");
+        sb.appendSeparator(standardSeparator, startSeparator);
+        assertThat(sb.toString()).isEqualTo(startSeparator);
+        sb.appendSeparator(null, null);
+        assertThat(sb.toString()).isEqualTo(startSeparator);
+        sb.appendSeparator(null, startSeparator);
+        assertThat(sb.toString()).isEqualTo(startSeparator);
+        sb.append(foo);
+        assertThat(sb.toString()).isEqualTo(startSeparator + foo);
+        sb.appendSeparator(standardSeparator, startSeparator);
+        assertThat(sb.toString()).isEqualTo(startSeparator + foo + standardSeparator);
+    }
 
-        sb.clear();
-        sb.appendAll(Collections.EMPTY_LIST.iterator());
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendWithNullText() {
+        final StrBuilder sb = new StrBuilder();
+        sb.setNullText("NULL");
         assertThat(sb.toString()).isEqualTo("");
 
-        sb.clear();
-        sb.appendAll(Arrays.asList("foo", "bar", "baz").iterator());
-        assertThat(sb.toString()).isEqualTo("foobarbaz");
+        sb.appendNull();
+        assertThat(sb.toString()).isEqualTo("NULL");
+
+        sb.append((Object) null);
+        assertThat(sb.toString()).isEqualTo("NULLNULL");
+
+        sb.append(FOO);
+        assertThat(sb.toString()).isEqualTo("NULLNULLfoo");
+
+        sb.append((String) null);
+        assertThat(sb.toString()).isEqualTo("NULLNULLfooNULL");
+
+        sb.append("");
+        assertThat(sb.toString()).isEqualTo("NULLNULLfooNULL");
+
+        sb.append("bar");
+        assertThat(sb.toString()).isEqualTo("NULLNULLfooNULLbar");
+
+        sb.append((StringBuffer) null);
+        assertThat(sb.toString()).isEqualTo("NULLNULLfooNULLbarNULL");
+
+        sb.append(new StringBuffer("baz"));
+        assertThat(sb.toString()).isEqualTo("NULLNULLfooNULLbarNULLbaz");
     }
 
     //-----------------------------------------------------------------------
@@ -1156,7 +1239,6 @@ public class StrBuilderAppendInsertTest {
         sb.appendWithSeparators(Arrays.asList("foo", null, "baz"), ",");
         assertThat(sb.toString()).isEqualTo("foo,,baz");
     }
-
     //-----------------------------------------------------------------------
     @Test
     public void testAppendWithSeparators_Iterator() {
@@ -1196,96 +1278,6 @@ public class StrBuilderAppendInsertTest {
 
     //-----------------------------------------------------------------------
     @Test
-    public void testAppendSeparator_String() {
-        final StrBuilder sb = new StrBuilder();
-        sb.appendSeparator(",");  // no effect
-        assertThat(sb.toString()).isEqualTo("");
-        sb.append("foo");
-        assertThat(sb.toString()).isEqualTo("foo");
-        sb.appendSeparator(",");
-        assertThat(sb.toString()).isEqualTo("foo,");
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendSeparator_String_String() {
-        final StrBuilder sb = new StrBuilder();
-        final String startSeparator = "order by ";
-        final String standardSeparator = ",";
-        final String foo = "foo";
-        sb.appendSeparator(null, null);
-        assertThat(sb.toString()).isEqualTo("");
-        sb.appendSeparator(standardSeparator, null);
-        assertThat(sb.toString()).isEqualTo("");
-        sb.appendSeparator(standardSeparator, startSeparator);
-        assertThat(sb.toString()).isEqualTo(startSeparator);
-        sb.appendSeparator(null, null);
-        assertThat(sb.toString()).isEqualTo(startSeparator);
-        sb.appendSeparator(null, startSeparator);
-        assertThat(sb.toString()).isEqualTo(startSeparator);
-        sb.append(foo);
-        assertThat(sb.toString()).isEqualTo(startSeparator + foo);
-        sb.appendSeparator(standardSeparator, startSeparator);
-        assertThat(sb.toString()).isEqualTo(startSeparator + foo + standardSeparator);
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendSeparator_char() {
-        final StrBuilder sb = new StrBuilder();
-        sb.appendSeparator(',');  // no effect
-        assertThat(sb.toString()).isEqualTo("");
-        sb.append("foo");
-        assertThat(sb.toString()).isEqualTo("foo");
-        sb.appendSeparator(',');
-        assertThat(sb.toString()).isEqualTo("foo,");
-    }
-    @Test
-    public void testAppendSeparator_char_char() {
-        final StrBuilder sb = new StrBuilder();
-        final char startSeparator = ':';
-        final char standardSeparator = ',';
-        final String foo = "foo";
-        sb.appendSeparator(standardSeparator, startSeparator);  // no effect
-        assertThat(sb.toString()).isEqualTo(String.valueOf(startSeparator));
-        sb.append(foo);
-        assertThat(sb.toString()).isEqualTo(String.valueOf(startSeparator) + foo);
-        sb.appendSeparator(standardSeparator, startSeparator);
-        assertThat(sb.toString()).isEqualTo(String.valueOf(startSeparator) + foo + standardSeparator);
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendSeparator_String_int() {
-        final StrBuilder sb = new StrBuilder();
-        sb.appendSeparator(",", 0);  // no effect
-        assertThat(sb.toString()).isEqualTo("");
-        sb.append("foo");
-        assertThat(sb.toString()).isEqualTo("foo");
-        sb.appendSeparator(",", 1);
-        assertThat(sb.toString()).isEqualTo("foo,");
-
-        sb.appendSeparator(",", -1);  // no effect
-        assertThat(sb.toString()).isEqualTo("foo,");
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendSeparator_char_int() {
-        final StrBuilder sb = new StrBuilder();
-        sb.appendSeparator(',', 0);  // no effect
-        assertThat(sb.toString()).isEqualTo("");
-        sb.append("foo");
-        assertThat(sb.toString()).isEqualTo("foo");
-        sb.appendSeparator(',', 1);
-        assertThat(sb.toString()).isEqualTo("foo,");
-
-        sb.appendSeparator(',', -1);  // no effect
-        assertThat(sb.toString()).isEqualTo("foo,");
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
     public void testInsert() {
 
         final StrBuilder sb = new StrBuilder();
@@ -1475,4 +1467,12 @@ public class StrBuilderAppendInsertTest {
         sb.insert(0, (char[]) null, 0, 0);
         assertThat(sb.toString()).isEqualTo("nullnullfoonullbarbaz");
     }
+
+    // See: https://issues.apache.org/jira/browse/LANG-299
+    @Test
+    public void testLang299() {
+        final StrBuilder sb = new StrBuilder(1);
+        sb.appendFixedWidthPadRight("foo", 1, '-');
+        assertThat(sb.toString()).isEqualTo("f");
+    }
 }
diff --git a/src/test/java/org/apache/commons/text/StrBuilderTest.java b/src/test/java/org/apache/commons/text/StrBuilderTest.java
index ca8aaa8..b9c8248 100644
--- a/src/test/java/org/apache/commons/text/StrBuilderTest.java
+++ b/src/test/java/org/apache/commons/text/StrBuilderTest.java
@@ -48,176 +48,376 @@ import org.junit.jupiter.api.Test;
 @Deprecated
 public class StrBuilderTest {
 
-    // -----------------------------------------------------------------------
-    @Test
-    public void testConstructors() {
-        final StrBuilder sb0 = new StrBuilder();
-        assertEquals(32, sb0.capacity());
-        assertEquals(0, sb0.length());
-        assertEquals(0, sb0.size());
-
-        final StrBuilder sb1 = new StrBuilder(32);
-        assertEquals(32, sb1.capacity());
-        assertEquals(0, sb1.length());
-        assertEquals(0, sb1.size());
-
-        final StrBuilder sb2 = new StrBuilder(0);
-        assertEquals(32, sb2.capacity());
-        assertEquals(0, sb2.length());
-        assertEquals(0, sb2.size());
+    private static class MockReadable implements Readable {
 
-        final StrBuilder sb3 = new StrBuilder(-1);
-        assertEquals(32, sb3.capacity());
-        assertEquals(0, sb3.length());
-        assertEquals(0, sb3.size());
+        private final CharBuffer src;
 
-        final StrBuilder sb4 = new StrBuilder(1);
-        assertEquals(1, sb4.capacity());
-        assertEquals(0, sb4.length());
-        assertEquals(0, sb4.size());
+        MockReadable(final String src) {
+            this.src = CharBuffer.wrap(src);
+        }
 
-        final StrBuilder sb5 = new StrBuilder((String) null);
-        assertEquals(32, sb5.capacity());
-        assertEquals(0, sb5.length());
-        assertEquals(0, sb5.size());
+        @Override
+        public int read(final CharBuffer cb) throws IOException {
+            return src.read(cb);
+        }
+    }
 
-        final StrBuilder sb6 = new StrBuilder("");
-        assertEquals(32, sb6.capacity());
-        assertEquals(0, sb6.length());
-        assertEquals(0, sb6.size());
+    static final StrMatcher A_NUMBER_MATCHER = new StrMatcher() {
 
-        final StrBuilder sb7 = new StrBuilder("foo");
-        assertEquals(35, sb7.capacity());
-        assertEquals(3, sb7.length());
-        assertEquals(3, sb7.size());
-    }
+        @Override
+        public int isMatch(final char[] buffer, int pos, final int bufferStart, final int bufferEnd) {
+            if (buffer[pos] == 'A') {
+                pos++;
+                if (pos < bufferEnd && buffer[pos] >= '0' && buffer[pos] <= '9') {
+                    return 2;
+                }
+            }
+            return 0;
+        }
+    };
 
-    // -----------------------------------------------------------------------
     @Test
-    public void testChaining() {
+    public void test_LANG_1131_EqualsWithNullStrBuilder() throws Exception {
         final StrBuilder sb = new StrBuilder();
-        assertSame(sb, sb.setNewLineText(null));
-        assertSame(sb, sb.setNullText(null));
-        assertSame(sb, sb.setLength(1));
-        assertSame(sb, sb.setCharAt(0, 'a'));
-        assertSame(sb, sb.ensureCapacity(0));
-        assertSame(sb, sb.minimizeCapacity());
-        assertSame(sb, sb.clear());
-        assertSame(sb, sb.reverse());
-        assertSame(sb, sb.trim());
+        final StrBuilder other = null;
+        assertFalse(sb.equals(other));
     }
 
     // -----------------------------------------------------------------------
     @Test
-    public void testReadFromReader() throws Exception {
-        String s = "";
-        for (int i = 0; i < 100; ++i) {
-            final StrBuilder sb = new StrBuilder();
-            final int len = sb.readFrom(new StringReader(s));
+    public void testAppendCharBuffer() {
+        final StrBuilder sb1 = new StrBuilder();
+        final CharBuffer buf = CharBuffer.allocate(10);
+        buf.append("0123456789");
+        buf.flip();
+        sb1.append(buf);
+        assertEquals("0123456789", sb1.toString());
 
-            assertEquals(s.length(), len);
-            assertEquals(s, sb.toString());
+        final StrBuilder sb2 = new StrBuilder();
+        sb2.append(buf, 1, 8);
+        assertEquals("12345678", sb2.toString());
+    }
 
-            s += Integer.toString(i);
+    @Test
+    public void testAppendCharBufferException() throws Exception {
+        final StrBuilder sb = new StrBuilder("1234567890");
+        final String text = "Test";
+        final CharBuffer buffer = CharBuffer.allocate(sb.size() + text.length());
+        buffer.put(text);
+        buffer.flip();
+        try {
+            sb.append(buffer, -1, 12);
+        } catch (final StringIndexOutOfBoundsException e) {
+            assertEquals("startIndex must be valid", e.getMessage());
         }
+
+        try {
+            sb.append(buffer, 0, -1);
+        } catch (final StringIndexOutOfBoundsException e) {
+            assertEquals("length must be valid", e.getMessage());
+        }
+
+        sb.append(buffer);
+        assertEquals("1234567890Test", sb.toString());
     }
 
     @Test
-    public void testReadFromReaderAppendsToEnd() throws Exception {
-        final StrBuilder sb = new StrBuilder("Test");
-        sb.readFrom(new StringReader(" 123"));
-        assertEquals("Test 123", sb.toString());
+    public void testAppendCharBufferNull() throws Exception {
+        final StrBuilder sb = new StrBuilder("1234567890");
+        final CharBuffer buffer = null;
+        sb.append(buffer);
+        assertEquals("1234567890", sb.toString());
+
+        final StrBuilder sb1 = new StrBuilder("1234567890");
+        final CharBuffer buffer1 = null;
+        sb.append(buffer1, 0, 0);
+        assertEquals("1234567890", sb1.toString());
     }
 
     @Test
-    public void testReadFromCharBuffer() throws Exception {
-        String s = "";
-        for (int i = 0; i < 100; ++i) {
-            final StrBuilder sb = new StrBuilder();
-            final int len = sb.readFrom(CharBuffer.wrap(s));
+    public void testAppendCharSequence() {
+        final CharSequence obj0 = null;
+        final CharSequence obj1 = new StrBuilder("test1");
+        final CharSequence obj2 = new StringBuilder("test2");
+        final CharSequence obj3 = new StringBuffer("test3");
+        final CharBuffer obj4 = CharBuffer.wrap("test4".toCharArray());
 
-            assertEquals(s.length(), len);
-            assertEquals(s, sb.toString());
+        final StrBuilder sb0 = new StrBuilder();
+        assertEquals("", sb0.append(obj0).toString());
 
-            s += Integer.toString(i);
-        }
+        final StrBuilder sb1 = new StrBuilder();
+        assertEquals("test1", sb1.append(obj1).toString());
+
+        final StrBuilder sb2 = new StrBuilder();
+        assertEquals("test2", sb2.append(obj2).toString());
+
+        final StrBuilder sb3 = new StrBuilder();
+        assertEquals("test3", sb3.append(obj3).toString());
+
+        final StrBuilder sb4 = new StrBuilder();
+        assertEquals("test4", sb4.append(obj4).toString());
+
+        final StrBuilder sb5 = new StrBuilder();
+        assertEquals("", sb5.append(obj0, 0, 0).toString());
     }
 
     @Test
-    public void testReadFromCharBufferAppendsToEnd() throws Exception {
-        final StrBuilder sb = new StrBuilder("Test");
-        sb.readFrom(CharBuffer.wrap(" 123"));
-        assertEquals("Test 123", sb.toString());
+    public void testAppendln() {
+        final StrBuilder sb1 = new StrBuilder();
+        final char ch = 'c';
+        assertEquals("c" + System.lineSeparator(), sb1.appendln(ch).toString());
     }
 
     @Test
-    public void testReadFromReadable() throws Exception {
-        String s = "";
-        for (int i = 0; i < 100; ++i) {
-            final StrBuilder sb = new StrBuilder();
-            final int len = sb.readFrom(new MockReadable(s));
-
-            assertEquals(s.length(), len);
-            assertEquals(s, sb.toString());
+    public void testAppendStringBuilderNull() {
+        final StrBuilder sb1 = new StrBuilder();
+        final StringBuilder b = null;
+        assertEquals("", sb1.append(b).toString());
 
-            s += Integer.toString(i);
-        }
+        final StrBuilder sb2 = new StrBuilder();
+        assertEquals("", sb2.append(b, 0, 0).toString());
     }
 
     @Test
-    public void testReadFromReadableAppendsToEnd() throws Exception {
-        final StrBuilder sb = new StrBuilder("Test");
-        sb.readFrom(new MockReadable(" 123"));
-        assertEquals("Test 123", sb.toString());
+    public void testAppendTakingTwoIntsWithIndexOutOfBoundsThrowsStringIndexOutOfBoundsExceptionTwo() {
+        assertThatExceptionOfType(StringIndexOutOfBoundsException.class).isThrownBy(() -> {
+            final Charset charset = Charset.defaultCharset();
+            final ByteBuffer byteBuffer = charset.encode("asdf");
+            final CharBuffer charBuffer = charset.decode(byteBuffer);
+
+            new StrBuilder().append(charBuffer, 933, 654);
+        });
     }
 
-    private static class MockReadable implements Readable {
+    @Test
+    public void testAppendTakingTwoIntsWithZeroThrowsStringIndexOutOfBoundsException() {
+        assertThatExceptionOfType(StringIndexOutOfBoundsException.class).isThrownBy(() -> {
+            final Charset charset = Charset.defaultCharset();
+            final ByteBuffer byteBuffer = charset.encode("end < start");
+            final CharBuffer charBuffer = charset.decode(byteBuffer);
 
-        private final CharBuffer src;
+            new StrBuilder(630).append(charBuffer, 0, 630);
+        });
+    }
 
-        MockReadable(final String src) {
-            this.src = CharBuffer.wrap(src);
-        }
+    @Test
+    public void testAppendToCharBuffer() throws Exception {
+        final StrBuilder sb = new StrBuilder("1234567890");
+        final String text = "Test ";
+        final CharBuffer buffer = CharBuffer.allocate(sb.size() + text.length());
+        buffer.put(text);
 
-        @Override
-        public int read(final CharBuffer cb) throws IOException {
-            return src.read(cb);
-        }
+        sb.appendTo(buffer);
+
+        buffer.flip();
+        assertEquals("Test 1234567890", buffer.toString());
     }
 
-    // -----------------------------------------------------------------------
     @Test
-    public void testGetSetNewLineText() {
-        final StrBuilder sb = new StrBuilder();
-        assertNull(sb.getNewLineText());
+    public void testAppendToStringBuffer() throws Exception {
+        final StrBuilder sb = new StrBuilder("1234567890");
+        final StringBuffer buffer = new StringBuffer("Test ");
 
-        sb.setNewLineText("#");
-        assertEquals("#", sb.getNewLineText());
+        sb.appendTo(buffer);
 
-        sb.setNewLineText("");
-        assertEquals("", sb.getNewLineText());
+        assertEquals("Test 1234567890", buffer.toString());
+    }
 
-        sb.setNewLineText((String) null);
-        assertNull(sb.getNewLineText());
+    @Test
+    public void testAppendToStringBuilder() throws Exception {
+        final StrBuilder sb = new StrBuilder("1234567890");
+        final StringBuilder builder = new StringBuilder("Test ");
+
+        sb.appendTo(builder);
+
+        assertEquals("Test 1234567890", builder.toString());
     }
 
     // -----------------------------------------------------------------------
     @Test
-    public void testGetSetNullText() {
-        final StrBuilder sb = new StrBuilder();
-        assertNull(sb.getNullText());
+    public void testAppendToWriter() throws Exception {
+        final StrBuilder sb = new StrBuilder("1234567890");
+        final StringWriter writer = new StringWriter();
+        writer.append("Test ");
 
-        sb.setNullText("null");
-        assertEquals("null", sb.getNullText());
+        sb.appendTo(writer);
 
-        sb.setNullText("");
-        assertNull(sb.getNullText());
+        assertEquals("Test 1234567890", writer.toString());
+    }
 
-        sb.setNullText("NULL");
-        assertEquals("NULL", sb.getNullText());
+    @Test
+    public void testAsBuilder() {
+        final StrBuilder sb = new StrBuilder().appendAll("Lorem", " ", "ipsum", " ", "dolor");
+        assertEquals(sb.toString(), sb.build());
+    }
 
-        sb.setNullText((String) null);
-        assertNull(sb.getNullText());
+    // -----------------------------------------------------------------------
+    @Test
+    public void testAsReader() throws Exception {
+        final StrBuilder sb = new StrBuilder("some text");
+        try (Reader reader = sb.asReader()) {
+            assertTrue(reader.ready());
+            final char[] buf = new char[40];
+            assertEquals(9, reader.read(buf));
+            assertEquals("some text", new String(buf, 0, 9));
+
+            assertEquals(-1, reader.read());
+            assertFalse(reader.ready());
+            assertEquals(0, reader.skip(2));
+            assertEquals(0, reader.skip(-1));
+
+            assertTrue(reader.markSupported());
+        }
+        try (Reader reader = sb.asReader()) {
+            assertEquals('s', reader.read());
+            reader.mark(-1);
+            char[] array = new char[3];
+            assertEquals(3, reader.read(array, 0, 3));
+            assertEquals('o', array[0]);
+            assertEquals('m', array[1]);
+            assertEquals('e', array[2]);
+            reader.reset();
+            assertEquals(1, reader.read(array, 1, 1));
+            assertEquals('o', array[0]);
+            assertEquals('o', array[1]);
+            assertEquals('e', array[2]);
+            assertEquals(2, reader.skip(2));
+            assertEquals(' ', reader.read());
+
+            assertTrue(reader.ready());
+            reader.close();
+            assertTrue(reader.ready());
+        }
+        try (Reader reader = sb.asReader()) {
+            char[] array = new char[3];
+            try {
+                reader.read(array, -1, 0);
+                fail("Exception expected!");
+            } catch (final IndexOutOfBoundsException ex) {
+                // expected
+            }
+            try {
+                reader.read(array, 0, -1);
+                fail("Exception expected!");
+            } catch (final IndexOutOfBoundsException ex) {
+                // expected
+            }
+            try {
+                reader.read(array, 100, 1);
+                fail("Exception expected!");
+            } catch (final IndexOutOfBoundsException ex) {
+                // expected
+            }
+            try {
+                reader.read(array, 0, 100);
+                fail("Exception expected!");
+            } catch (final IndexOutOfBoundsException ex) {
+                // expected
+            }
+            try {
+                reader.read(array, Integer.MAX_VALUE, Integer.MAX_VALUE);
+                fail("Exception expected!");
+            } catch (final IndexOutOfBoundsException ex) {
+                // expected
+            }
+
+            assertEquals(0, reader.read(array, 0, 0));
+            assertEquals(0, array[0]);
+            assertEquals(0, array[1]);
+            assertEquals(0, array[2]);
+
+            reader.skip(9);
+            assertEquals(-1, reader.read(array, 0, 1));
+
+            reader.reset();
+            array = new char[30];
+            assertEquals(9, reader.read(array, 0, 30));
+        }
+    }
+
+    // -----------------------------------------------------------------------
+    @Test
+    public void testAsTokenizer() throws Exception {
+        // from Javadoc
+        final StrBuilder b = new StrBuilder();
+        b.append("a b ");
+        final StrTokenizer t = b.asTokenizer();
+
+        final String[] tokens1 = t.getTokenArray();
+        assertEquals(2, tokens1.length);
+        assertEquals("a", tokens1[0]);
+        assertEquals("b", tokens1[1]);
+        assertEquals(2, t.size());
+
+        b.append("c d ");
+        final String[] tokens2 = t.getTokenArray();
+        assertEquals(2, tokens2.length);
+        assertEquals("a", tokens2[0]);
+        assertEquals("b", tokens2[1]);
+        assertEquals(2, t.size());
+        assertEquals("a", t.next());
+        assertEquals("b", t.next());
+
+        t.reset();
+        final String[] tokens3 = t.getTokenArray();
+        assertEquals(4, tokens3.length);
+        assertEquals("a", tokens3[0]);
+        assertEquals("b", tokens3[1]);
+        assertEquals("c", tokens3[2]);
+        assertEquals("d", tokens3[3]);
+        assertEquals(4, t.size());
+        assertEquals("a", t.next());
+        assertEquals("b", t.next());
+        assertEquals("c", t.next());
+        assertEquals("d", t.next());
+
+        assertEquals("a b c d ", t.getContent());
+    }
+
+    // -----------------------------------------------------------------------
+    @Test
+    public void testAsWriter() throws Exception {
+        final StrBuilder sb = new StrBuilder("base");
+        try (Writer writer = sb.asWriter()) {
+
+            writer.write('l');
+            assertEquals("basel", sb.toString());
+
+            writer.write(new char[] {'i', 'n'});
+            assertEquals("baselin", sb.toString());
+
+            writer.write(new char[] {'n', 'e', 'r'}, 1, 2);
+            assertEquals("baseliner", sb.toString());
+
+            writer.write(" rout");
+            assertEquals("baseliner rout", sb.toString());
+
+            writer.write("ping that server", 1, 3);
+            assertEquals("baseliner routing", sb.toString());
+
+            writer.flush(); // no effect
+            assertEquals("baseliner routing", sb.toString());
+
+            writer.close(); // no effect
+            assertEquals("baseliner routing", sb.toString());
+
+            writer.write(" hi"); // works after close
+            assertEquals("baseliner routing hi", sb.toString());
+
+            sb.setLength(4); // mix and match
+            writer.write('d');
+            assertEquals("based", sb.toString());
+        }
+    }
+
+    // -----------------------------------------------------------------------
+    @Test
+    public void testCapacity() {
+        final StrBuilder sb = new StrBuilder();
+        assertEquals(sb.buffer.length, sb.capacity());
+
+        sb.append("HelloWorldHelloWorldHelloWorldHelloWorld");
+        assertEquals(sb.buffer.length, sb.capacity());
     }
 
     // -----------------------------------------------------------------------
@@ -302,261 +502,119 @@ public class StrBuilderTest {
 
     // -----------------------------------------------------------------------
     @Test
-    public void testLength() {
-        final StrBuilder sb = new StrBuilder();
-        assertEquals(0, sb.length());
-
-        sb.append("Hello");
-        assertEquals(5, sb.length());
-    }
-
-    @Test
-    public void testSetLength() {
+    public void testChaining() {
         final StrBuilder sb = new StrBuilder();
-        sb.append("Hello");
-        sb.setLength(2); // shorten
-        assertEquals("He", sb.toString());
-        sb.setLength(2); // no change
-        assertEquals("He", sb.toString());
-        sb.setLength(3); // lengthen
-        assertEquals("He\0", sb.toString());
-
-        assertThrows(IndexOutOfBoundsException.class, () -> sb.setLength(-1));
+        assertSame(sb, sb.setNewLineText(null));
+        assertSame(sb, sb.setNullText(null));
+        assertSame(sb, sb.setLength(1));
+        assertSame(sb, sb.setCharAt(0, 'a'));
+        assertSame(sb, sb.ensureCapacity(0));
+        assertSame(sb, sb.minimizeCapacity());
+        assertSame(sb, sb.clear());
+        assertSame(sb, sb.reverse());
+        assertSame(sb, sb.trim());
     }
 
     // -----------------------------------------------------------------------
     @Test
-    public void testCapacity() {
+    public void testCharAt() {
         final StrBuilder sb = new StrBuilder();
-        assertEquals(sb.buffer.length, sb.capacity());
-
-        sb.append("HelloWorldHelloWorldHelloWorldHelloWorld");
-        assertEquals(sb.buffer.length, sb.capacity());
+        assertThrows(IndexOutOfBoundsException.class, () -> sb.charAt(0));
+        assertThrows(IndexOutOfBoundsException.class, () -> sb.charAt(-1));
+        sb.append("foo");
+        assertEquals('f', sb.charAt(0));
+        assertEquals('o', sb.charAt(1));
+        assertEquals('o', sb.charAt(2));
+        assertThrows(IndexOutOfBoundsException.class, () -> sb.charAt(-1));
+        assertThrows(IndexOutOfBoundsException.class, () -> sb.charAt(3));
     }
 
     @Test
-    public void testEnsureCapacity() {
+    public void testClear() {
         final StrBuilder sb = new StrBuilder();
-        sb.ensureCapacity(2);
-        assertTrue(sb.capacity() >= 2);
-
-        sb.ensureCapacity(-1);
-        assertTrue(sb.capacity() >= 0);
-
-        sb.append("HelloWorld");
-        sb.ensureCapacity(40);
-        assertTrue(sb.capacity() >= 40);
+        sb.append("Hello");
+        sb.clear();
+        assertEquals(0, sb.length());
+        assertTrue(sb.buffer.length >= 5);
     }
 
+    // -----------------------------------------------------------------------
     @Test
-    public void testMinimizeCapacity() {
-        final StrBuilder sb = new StrBuilder();
-        sb.minimizeCapacity();
-        assertEquals(0, sb.capacity());
+    public void testConstructors() {
+        final StrBuilder sb0 = new StrBuilder();
+        assertEquals(32, sb0.capacity());
+        assertEquals(0, sb0.length());
+        assertEquals(0, sb0.size());
 
-        sb.append("HelloWorld");
-        sb.minimizeCapacity();
-        assertEquals(10, sb.capacity());
-    }
+        final StrBuilder sb1 = new StrBuilder(32);
+        assertEquals(32, sb1.capacity());
+        assertEquals(0, sb1.length());
+        assertEquals(0, sb1.size());
 
-    // -----------------------------------------------------------------------
-    @Test
-    public void testSize() {
-        final StrBuilder sb = new StrBuilder();
-        assertEquals(0, sb.size());
-
-        sb.append("Hello");
-        assertEquals(5, sb.size());
-    }
-
-    @Test
-    public void testIsEmpty() {
-        final StrBuilder sb = new StrBuilder();
-        assertTrue(sb.isEmpty());
-
-        sb.append("Hello");
-        assertFalse(sb.isEmpty());
-
-        sb.clear();
-        assertTrue(sb.isEmpty());
-    }
+        final StrBuilder sb2 = new StrBuilder(0);
+        assertEquals(32, sb2.capacity());
+        assertEquals(0, sb2.length());
+        assertEquals(0, sb2.size());
 
-    @Test
-    public void testClear() {
-        final StrBuilder sb = new StrBuilder();
-        sb.append("Hello");
-        sb.clear();
-        assertEquals(0, sb.length());
-        assertTrue(sb.buffer.length >= 5);
-    }
+        final StrBuilder sb3 = new StrBuilder(-1);
+        assertEquals(32, sb3.capacity());
+        assertEquals(0, sb3.length());
+        assertEquals(0, sb3.size());
 
-    // -----------------------------------------------------------------------
-    @Test
-    public void testCharAt() {
-        final StrBuilder sb = new StrBuilder();
-        assertThrows(IndexOutOfBoundsException.class, () -> sb.charAt(0));
-        assertThrows(IndexOutOfBoundsException.class, () -> sb.charAt(-1));
-        sb.append("foo");
-        assertEquals('f', sb.charAt(0));
-        assertEquals('o', sb.charAt(1));
-        assertEquals('o', sb.charAt(2));
-        assertThrows(IndexOutOfBoundsException.class, () -> sb.charAt(-1));
-        assertThrows(IndexOutOfBoundsException.class, () -> sb.charAt(3));
-    }
+        final StrBuilder sb4 = new StrBuilder(1);
+        assertEquals(1, sb4.capacity());
+        assertEquals(0, sb4.length());
+        assertEquals(0, sb4.size());
 
-    // -----------------------------------------------------------------------
-    @Test
-    public void testSetCharAt() {
-        final StrBuilder sb = new StrBuilder();
-        assertThrows(IndexOutOfBoundsException.class, () -> sb.setCharAt(0, 'f'));
-        assertThrows(IndexOutOfBoundsException.class, () -> sb.setCharAt(-1, 'f'));
-        sb.append("foo");
-        sb.setCharAt(0, 'b');
-        sb.setCharAt(1, 'a');
-        sb.setCharAt(2, 'r');
-        assertThrows(IndexOutOfBoundsException.class, () -> sb.setCharAt(3, '!'));
-        assertEquals("bar", sb.toString());
-    }
+        final StrBuilder sb5 = new StrBuilder((String) null);
+        assertEquals(32, sb5.capacity());
+        assertEquals(0, sb5.length());
+        assertEquals(0, sb5.size());
 
-    // -----------------------------------------------------------------------
-    @Test
-    public void testDeleteCharAt() {
-        final StrBuilder sb = new StrBuilder("abc");
-        sb.deleteCharAt(0);
-        assertEquals("bc", sb.toString());
+        final StrBuilder sb6 = new StrBuilder("");
+        assertEquals(32, sb6.capacity());
+        assertEquals(0, sb6.length());
+        assertEquals(0, sb6.size());
 
-        assertThrows(IndexOutOfBoundsException.class, () -> sb.deleteCharAt(1000));
+        final StrBuilder sb7 = new StrBuilder("foo");
+        assertEquals(35, sb7.capacity());
+        assertEquals(3, sb7.length());
+        assertEquals(3, sb7.size());
     }
 
     // -----------------------------------------------------------------------
     @Test
-    public void testToCharArray() {
-        final StrBuilder sb = new StrBuilder();
-        assertEquals(0, sb.toCharArray().length);
-
-        char[] a = sb.toCharArray();
-        assertNotNull(a, "toCharArray() result is null");
-        assertEquals(0, a.length, "toCharArray() result is too large");
-
-        sb.append("junit");
-        a = sb.toCharArray();
-        assertEquals(5, a.length, "toCharArray() result incorrect length");
-        assertTrue(Arrays.equals("junit".toCharArray(), a), "toCharArray() result does not match");
-    }
-
-    @Test
-    public void testToCharArrayIntInt() {
-        final StrBuilder sb = new StrBuilder();
-        assertEquals(0, sb.toCharArray(0, 0).length);
-
-        sb.append("junit");
-        char[] a = sb.toCharArray(0, 20); // too large test
-        assertEquals(5, a.length, "toCharArray(int,int) result incorrect length");
-        assertTrue(Arrays.equals("junit".toCharArray(), a), "toCharArray(int,int) result does not match");
-
-        a = sb.toCharArray(0, 4);
-        assertEquals(4, a.length, "toCharArray(int,int) result incorrect length");
-        assertTrue(Arrays.equals("juni".toCharArray(), a), "toCharArray(int,int) result does not match");
-
-        a = sb.toCharArray(0, 4);
-        assertEquals(4, a.length, "toCharArray(int,int) result incorrect length");
-        assertTrue(Arrays.equals("juni".toCharArray(), a), "toCharArray(int,int) result does not match");
-
-        a = sb.toCharArray(0, 1);
-        assertNotNull(a, "toCharArray(int,int) result is null");
-
-        assertThrows(IndexOutOfBoundsException.class, () -> sb.toCharArray(-1, 5));
-
-        assertThrows(IndexOutOfBoundsException.class, () -> sb.toCharArray(6, 5));
-    }
-
-    @Test
-    public void testGetChars() {
-        final StrBuilder sb = new StrBuilder();
-
-        char[] input = new char[10];
-        char[] a = sb.getChars(input);
-        assertSame(input, a);
-        assertTrue(Arrays.equals(new char[10], a));
-
-        sb.append("junit");
-        a = sb.getChars(input);
-        assertSame(input, a);
-        assertTrue(Arrays.equals(new char[] {'j', 'u', 'n', 'i', 't', 0, 0, 0, 0, 0 }, a));
-
-        a = sb.getChars(null);
-        assertNotSame(input, a);
-        assertEquals(5, a.length);
-        assertTrue(Arrays.equals("junit".toCharArray(), a));
-
-        input = new char[5];
-        a = sb.getChars(input);
-        assertSame(input, a);
-
-        input = new char[4];
-        a = sb.getChars(input);
-        assertNotSame(input, a);
+    public void testContains_char() {
+        final StrBuilder sb = new StrBuilder("abcdefghijklmnopqrstuvwxyz");
+        assertTrue(sb.contains('a'));
+        assertTrue(sb.contains('o'));
+        assertTrue(sb.contains('z'));
+        assertFalse(sb.contains('1'));
     }
 
     @Test
-    public void testGetCharsIntIntCharArrayInt() {
-        final StrBuilder sb = new StrBuilder();
-
-        sb.append("junit");
-        char[] a = new char[5];
-        sb.getChars(0, 5, a, 0);
-        assertTrue(Arrays.equals(new char[] {'j', 'u', 'n', 'i', 't' }, a));
-
-        a = new char[5];
-        sb.getChars(0, 2, a, 3);
-        assertTrue(Arrays.equals(new char[] {0, 0, 0, 'j', 'u' }, a));
-
-        try {
-            sb.getChars(-1, 0, a, 0);
-            fail("no exception");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.getChars(0, -1, a, 0);
-            fail("no exception");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.getChars(0, 20, a, 0);
-            fail("no exception");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.getChars(4, 2, a, 0);
-            fail("no exception");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
+    public void testContains_String() {
+        final StrBuilder sb = new StrBuilder("abcdefghijklmnopqrstuvwxyz");
+        assertTrue(sb.contains("a"));
+        assertTrue(sb.contains("pq"));
+        assertTrue(sb.contains("z"));
+        assertFalse(sb.contains("zyx"));
+        assertFalse(sb.contains((String) null));
     }
 
-    // -----------------------------------------------------------------------
     @Test
-    public void testDeleteIntInt() {
-        final StrBuilder sb = new StrBuilder("abc");
-        sb.delete(0, 1);
-        assertEquals("bc", sb.toString());
-        sb.delete(1, 2);
-        assertEquals("b", sb.toString());
-        sb.delete(0, 1);
-        assertEquals("", sb.toString());
-        sb.delete(0, 1000);
-        assertEquals("", sb.toString());
-
-        assertThrows(IndexOutOfBoundsException.class, () -> sb.delete(1, 2));
-        assertThrows(IndexOutOfBoundsException.class, () -> sb.delete(-1, 1));
+    public void testContains_StrMatcher() {
+        StrBuilder sb = new StrBuilder("abcdefghijklmnopqrstuvwxyz");
+        assertTrue(sb.contains(StrMatcher.charMatcher('a')));
+        assertTrue(sb.contains(StrMatcher.stringMatcher("pq")));
+        assertTrue(sb.contains(StrMatcher.charMatcher('z')));
+        assertFalse(sb.contains(StrMatcher.stringMatcher("zy")));
+        assertFalse(sb.contains((StrMatcher) null));
 
-        assertThrows(IndexOutOfBoundsException.class, () -> new StrBuilder("anything").delete(2, 1));
+        sb = new StrBuilder();
+        assertFalse(sb.contains(A_NUMBER_MATCHER));
+        sb.append("B A1 C");
+        assertTrue(sb.contains(A_NUMBER_MATCHER));
     }
 
     // -----------------------------------------------------------------------
@@ -577,23 +635,6 @@ public class StrBuilderTest {
         assertEquals("", sb.toString());
     }
 
-    @Test
-    public void testDeleteFirst_char() {
-        StrBuilder sb = new StrBuilder("abcba");
-        sb.deleteFirst('X');
-        assertEquals("abcba", sb.toString());
-        sb.deleteFirst('a');
-        assertEquals("bcba", sb.toString());
-        sb.deleteFirst('c');
-        assertEquals("bba", sb.toString());
-        sb.deleteFirst('b');
-        assertEquals("ba", sb.toString());
-
-        sb = new StrBuilder("");
-        sb.deleteFirst('b');
-        assertEquals("", sb.toString());
-    }
-
     // -----------------------------------------------------------------------
     @Test
     public void testDeleteAll_String() {
@@ -621,15 +662,67 @@ public class StrBuilderTest {
         assertEquals("", sb.toString());
     }
 
+    // -----------------------------------------------------------------------
     @Test
-    public void testDeleteFirst_String() {
-        StrBuilder sb = new StrBuilder("abcbccba");
-        sb.deleteFirst((String) null);
-        assertEquals("abcbccba", sb.toString());
-        sb.deleteFirst("");
-        assertEquals("abcbccba", sb.toString());
-
-        sb.deleteFirst("X");
+    public void testDeleteAll_StrMatcher() {
+        StrBuilder sb = new StrBuilder("A0xA1A2yA3");
+        sb.deleteAll((StrMatcher) null);
+        assertEquals("A0xA1A2yA3", sb.toString());
+        sb.deleteAll(A_NUMBER_MATCHER);
+        assertEquals("xy", sb.toString());
+
+        sb = new StrBuilder("Ax1");
+        sb.deleteAll(A_NUMBER_MATCHER);
+        assertEquals("Ax1", sb.toString());
+
+        sb = new StrBuilder("");
+        sb.deleteAll(A_NUMBER_MATCHER);
+        assertEquals("", sb.toString());
+    }
+
+    // -----------------------------------------------------------------------
+    @Test
+    public void testDeleteCharAt() {
+        final StrBuilder sb = new StrBuilder("abc");
+        sb.deleteCharAt(0);
+        assertEquals("bc", sb.toString());
+
+        assertThrows(IndexOutOfBoundsException.class, () -> sb.deleteCharAt(1000));
+    }
+
+    @Test
+    public void testDeleteCharAtWithNegative() {
+        assertThatExceptionOfType(StringIndexOutOfBoundsException.class).isThrownBy(() -> {
+            new StrBuilder().deleteCharAt((-1258));
+        });
+    }
+
+    @Test
+    public void testDeleteFirst_char() {
+        StrBuilder sb = new StrBuilder("abcba");
+        sb.deleteFirst('X');
+        assertEquals("abcba", sb.toString());
+        sb.deleteFirst('a');
+        assertEquals("bcba", sb.toString());
+        sb.deleteFirst('c');
+        assertEquals("bba", sb.toString());
+        sb.deleteFirst('b');
+        assertEquals("ba", sb.toString());
+
+        sb = new StrBuilder("");
+        sb.deleteFirst('b');
+        assertEquals("", sb.toString());
+    }
+
+    @Test
+    public void testDeleteFirst_String() {
+        StrBuilder sb = new StrBuilder("abcbccba");
+        sb.deleteFirst((String) null);
+        assertEquals("abcbccba", sb.toString());
+        sb.deleteFirst("");
+        assertEquals("abcbccba", sb.toString());
+
+        sb.deleteFirst("X");
         assertEquals("abcbccba", sb.toString());
         sb.deleteFirst("a");
         assertEquals("bcbccba", sb.toString());
@@ -647,24 +740,6 @@ public class StrBuilderTest {
         assertEquals("", sb.toString());
     }
 
-    // -----------------------------------------------------------------------
-    @Test
-    public void testDeleteAll_StrMatcher() {
-        StrBuilder sb = new StrBuilder("A0xA1A2yA3");
-        sb.deleteAll((StrMatcher) null);
-        assertEquals("A0xA1A2yA3", sb.toString());
-        sb.deleteAll(A_NUMBER_MATCHER);
-        assertEquals("xy", sb.toString());
-
-        sb = new StrBuilder("Ax1");
-        sb.deleteAll(A_NUMBER_MATCHER);
-        assertEquals("Ax1", sb.toString());
-
-        sb = new StrBuilder("");
-        sb.deleteAll(A_NUMBER_MATCHER);
-        assertEquals("", sb.toString());
-    }
-
     @Test
     public void testDeleteFirst_StrMatcher() {
         StrBuilder sb = new StrBuilder("A0xA1A2yA3");
@@ -684,633 +759,440 @@ public class StrBuilderTest {
 
     // -----------------------------------------------------------------------
     @Test
-    public void testReplace_int_int_String() {
-        StrBuilder sb = new StrBuilder("abc");
-        sb.replace(0, 1, "d");
-        assertEquals("dbc", sb.toString());
-        sb.replace(0, 1, "aaa");
-        assertEquals("aaabc", sb.toString());
-        sb.replace(0, 3, "");
+    public void testDeleteIntInt() {
+        final StrBuilder sb = new StrBuilder("abc");
+        sb.delete(0, 1);
         assertEquals("bc", sb.toString());
-        sb.replace(1, 2, (String) null);
+        sb.delete(1, 2);
         assertEquals("b", sb.toString());
-        sb.replace(1, 1000, "text");
-        assertEquals("btext", sb.toString());
-        sb.replace(0, 1000, "text");
-        assertEquals("text", sb.toString());
+        sb.delete(0, 1);
+        assertEquals("", sb.toString());
+        sb.delete(0, 1000);
+        assertEquals("", sb.toString());
 
-        sb = new StrBuilder("atext");
-        sb.replace(1, 1, "ny");
-        assertEquals("anytext", sb.toString());
-        try {
-            sb.replace(2, 1, "anything");
-            fail("Expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
+        assertThrows(IndexOutOfBoundsException.class, () -> sb.delete(1, 2));
+        assertThrows(IndexOutOfBoundsException.class, () -> sb.delete(-1, 1));
 
-        sb = new StrBuilder();
-        try {
-            sb.replace(1, 2, "anything");
-            fail("Expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-        try {
-            sb.replace(-1, 1, "anything");
-            fail("Expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
+        assertThrows(IndexOutOfBoundsException.class, () -> new StrBuilder("anything").delete(2, 1));
     }
 
-    // -----------------------------------------------------------------------
     @Test
-    public void testReplaceAll_char_char() {
-        final StrBuilder sb = new StrBuilder("abcbccba");
-        sb.replaceAll('x', 'y');
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceAll('a', 'd');
-        assertEquals("dbcbccbd", sb.toString());
-        sb.replaceAll('b', 'e');
-        assertEquals("dececced", sb.toString());
-        sb.replaceAll('c', 'f');
-        assertEquals("defeffed", sb.toString());
-        sb.replaceAll('d', 'd');
-        assertEquals("defeffed", sb.toString());
+    public void testEndsWith() {
+        final StrBuilder sb = new StrBuilder();
+        assertFalse(sb.endsWith("a"));
+        assertFalse(sb.endsWith("c"));
+        assertTrue(sb.endsWith(""));
+        assertFalse(sb.endsWith(null));
+        sb.append("abc");
+        assertTrue(sb.endsWith("c"));
+        assertTrue(sb.endsWith("bc"));
+        assertTrue(sb.endsWith("abc"));
+        assertFalse(sb.endsWith("cba"));
+        assertFalse(sb.endsWith("abcd"));
+        assertFalse(sb.endsWith(" abc"));
+        assertFalse(sb.endsWith("abc "));
     }
 
-    // -----------------------------------------------------------------------
     @Test
-    public void testReplaceFirst_char_char() {
-        final StrBuilder sb = new StrBuilder("abcbccba");
-        sb.replaceFirst('x', 'y');
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceFirst('a', 'd');
-        assertEquals("dbcbccba", sb.toString());
-        sb.replaceFirst('b', 'e');
-        assertEquals("decbccba", sb.toString());
-        sb.replaceFirst('c', 'f');
-        assertEquals("defbccba", sb.toString());
-        sb.replaceFirst('d', 'd');
-        assertEquals("defbccba", sb.toString());
+    public void testEnsureCapacity() {
+        final StrBuilder sb = new StrBuilder();
+        sb.ensureCapacity(2);
+        assertTrue(sb.capacity() >= 2);
+
+        sb.ensureCapacity(-1);
+        assertTrue(sb.capacity() >= 0);
+
+        sb.append("HelloWorld");
+        sb.ensureCapacity(40);
+        assertTrue(sb.capacity() >= 40);
     }
 
     // -----------------------------------------------------------------------
     @Test
-    public void testReplaceAll_String_String() {
-        StrBuilder sb = new StrBuilder("abcbccba");
-        sb.replaceAll((String) null, null);
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceAll((String) null, "anything");
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceAll("", null);
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceAll("", "anything");
-        assertEquals("abcbccba", sb.toString());
+    public void testEquals() {
+        final StrBuilder sb1 = new StrBuilder();
+        final StrBuilder sb2 = new StrBuilder();
+        assertTrue(sb1.equals(sb2));
+        assertTrue(sb1.equals(sb1));
+        assertTrue(sb2.equals(sb2));
+        assertTrue(sb1.equals((Object) sb2));
 
-        sb.replaceAll("x", "y");
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceAll("a", "d");
-        assertEquals("dbcbccbd", sb.toString());
-        sb.replaceAll("d", null);
-        assertEquals("bcbccb", sb.toString());
-        sb.replaceAll("cb", "-");
-        assertEquals("b-c-", sb.toString());
+        sb1.append("abc");
+        assertFalse(sb1.equals(sb2));
+        assertFalse(sb1.equals((Object) sb2));
 
-        sb = new StrBuilder("abcba");
-        sb.replaceAll("b", "xbx");
-        assertEquals("axbxcxbxa", sb.toString());
+        sb2.append("ABC");
+        assertFalse(sb1.equals(sb2));
+        assertFalse(sb1.equals((Object) sb2));
 
-        sb = new StrBuilder("bb");
-        sb.replaceAll("b", "xbx");
-        assertEquals("xbxxbx", sb.toString());
+        sb2.clear().append("abc");
+        assertTrue(sb1.equals(sb2));
+        assertTrue(sb1.equals((Object) sb2));
+
+        assertFalse(sb1.equals(Integer.valueOf(1)));
+        assertFalse(sb1.equals("abc"));
     }
 
+    // -----------------------------------------------------------------------
     @Test
-    public void testReplaceFirst_String_String() {
-        StrBuilder sb = new StrBuilder("abcbccba");
-        sb.replaceFirst((String) null, null);
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceFirst((String) null, "anything");
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceFirst("", null);
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceFirst("", "anything");
-        assertEquals("abcbccba", sb.toString());
+    public void testEqualsIgnoreCase() {
+        final StrBuilder sb1 = new StrBuilder();
+        final StrBuilder sb2 = new StrBuilder();
+        assertTrue(sb1.equalsIgnoreCase(sb1));
+        assertTrue(sb1.equalsIgnoreCase(sb2));
+        assertTrue(sb2.equalsIgnoreCase(sb2));
 
-        sb.replaceFirst("x", "y");
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceFirst("a", "d");
-        assertEquals("dbcbccba", sb.toString());
-        sb.replaceFirst("d", null);
-        assertEquals("bcbccba", sb.toString());
-        sb.replaceFirst("cb", "-");
-        assertEquals("b-ccba", sb.toString());
+        sb1.append("abc");
+        assertFalse(sb1.equalsIgnoreCase(sb2));
 
-        sb = new StrBuilder("abcba");
-        sb.replaceFirst("b", "xbx");
-        assertEquals("axbxcba", sb.toString());
+        sb2.append("ABC");
+        assertTrue(sb1.equalsIgnoreCase(sb2));
 
-        sb = new StrBuilder("bb");
-        sb.replaceFirst("b", "xbx");
-        assertEquals("xbxb", sb.toString());
-    }
+        sb2.clear().append("abc");
+        assertTrue(sb1.equalsIgnoreCase(sb2));
+        assertTrue(sb1.equalsIgnoreCase(sb1));
+        assertTrue(sb2.equalsIgnoreCase(sb2));
+
+        sb2.clear().append("aBc");
+        assertTrue(sb1.equalsIgnoreCase(sb2));
+    }
 
-    // -----------------------------------------------------------------------
     @Test
-    public void testReplaceAll_StrMatcher_String() {
-        StrBuilder sb = new StrBuilder("abcbccba");
-        sb.replaceAll((StrMatcher) null, null);
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceAll((StrMatcher) null, "anything");
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceAll(StrMatcher.noneMatcher(), null);
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceAll(StrMatcher.noneMatcher(), "anything");
-        assertEquals("abcbccba", sb.toString());
+    public void testGetChars() {
+        final StrBuilder sb = new StrBuilder();
 
-        sb.replaceAll(StrMatcher.charMatcher('x'), "y");
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceAll(StrMatcher.charMatcher('a'), "d");
-        assertEquals("dbcbccbd", sb.toString());
-        sb.replaceAll(StrMatcher.charMatcher('d'), null);
-        assertEquals("bcbccb", sb.toString());
-        sb.replaceAll(StrMatcher.stringMatcher("cb"), "-");
-        assertEquals("b-c-", sb.toString());
+        char[] input = new char[10];
+        char[] a = sb.getChars(input);
+        assertSame(input, a);
+        assertTrue(Arrays.equals(new char[10], a));
 
-        sb = new StrBuilder("abcba");
-        sb.replaceAll(StrMatcher.charMatcher('b'), "xbx");
-        assertEquals("axbxcxbxa", sb.toString());
+        sb.append("junit");
+        a = sb.getChars(input);
+        assertSame(input, a);
+        assertTrue(Arrays.equals(new char[] {'j', 'u', 'n', 'i', 't', 0, 0, 0, 0, 0 }, a));
 
-        sb = new StrBuilder("bb");
-        sb.replaceAll(StrMatcher.charMatcher('b'), "xbx");
-        assertEquals("xbxxbx", sb.toString());
+        a = sb.getChars(null);
+        assertNotSame(input, a);
+        assertEquals(5, a.length);
+        assertTrue(Arrays.equals("junit".toCharArray(), a));
 
-        sb = new StrBuilder("A1-A2A3-A4");
-        sb.replaceAll(A_NUMBER_MATCHER, "***");
-        assertEquals("***-******-***", sb.toString());
+        input = new char[5];
+        a = sb.getChars(input);
+        assertSame(input, a);
 
-        sb = new StrBuilder("Dear X, hello X.");
-        sb.replaceAll(StrMatcher.stringMatcher("X"), "012345678901234567");
-        assertEquals("Dear 012345678901234567, hello 012345678901234567.", sb.toString());
+        input = new char[4];
+        a = sb.getChars(input);
+        assertNotSame(input, a);
     }
 
     @Test
-    public void testReplaceFirst_StrMatcher_String() {
-        StrBuilder sb = new StrBuilder("abcbccba");
-        sb.replaceFirst((StrMatcher) null, null);
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceFirst((StrMatcher) null, "anything");
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceFirst(StrMatcher.noneMatcher(), null);
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceFirst(StrMatcher.noneMatcher(), "anything");
-        assertEquals("abcbccba", sb.toString());
+    public void testGetCharsIntIntCharArrayInt() {
+        final StrBuilder sb = new StrBuilder();
 
-        sb.replaceFirst(StrMatcher.charMatcher('x'), "y");
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceFirst(StrMatcher.charMatcher('a'), "d");
-        assertEquals("dbcbccba", sb.toString());
-        sb.replaceFirst(StrMatcher.charMatcher('d'), null);
-        assertEquals("bcbccba", sb.toString());
-        sb.replaceFirst(StrMatcher.stringMatcher("cb"), "-");
-        assertEquals("b-ccba", sb.toString());
+        sb.append("junit");
+        char[] a = new char[5];
+        sb.getChars(0, 5, a, 0);
+        assertTrue(Arrays.equals(new char[] {'j', 'u', 'n', 'i', 't' }, a));
 
-        sb = new StrBuilder("abcba");
-        sb.replaceFirst(StrMatcher.charMatcher('b'), "xbx");
-        assertEquals("axbxcba", sb.toString());
+        a = new char[5];
+        sb.getChars(0, 2, a, 3);
+        assertTrue(Arrays.equals(new char[] {0, 0, 0, 'j', 'u' }, a));
 
-        sb = new StrBuilder("bb");
-        sb.replaceFirst(StrMatcher.charMatcher('b'), "xbx");
-        assertEquals("xbxb", sb.toString());
+        try {
+            sb.getChars(-1, 0, a, 0);
+            fail("no exception");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
 
-        sb = new StrBuilder("A1-A2A3-A4");
-        sb.replaceFirst(A_NUMBER_MATCHER, "***");
-        assertEquals("***-A2A3-A4", sb.toString());
+        try {
+            sb.getChars(0, -1, a, 0);
+            fail("no exception");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.getChars(0, 20, a, 0);
+            fail("no exception");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.getChars(4, 2, a, 0);
+            fail("no exception");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
     }
 
     // -----------------------------------------------------------------------
     @Test
-    public void testReplace_StrMatcher_String_int_int_int_VaryMatcher() {
-        StrBuilder sb = new StrBuilder("abcbccba");
-        sb.replace((StrMatcher) null, "x", 0, sb.length(), -1);
-        assertEquals("abcbccba", sb.toString());
-
-        sb.replace(StrMatcher.charMatcher('a'), "x", 0, sb.length(), -1);
-        assertEquals("xbcbccbx", sb.toString());
+    public void testGetSetNewLineText() {
+        final StrBuilder sb = new StrBuilder();
+        assertNull(sb.getNewLineText());
 
-        sb.replace(StrMatcher.stringMatcher("cb"), "x", 0, sb.length(), -1);
-        assertEquals("xbxcxx", sb.toString());
+        sb.setNewLineText("#");
+        assertEquals("#", sb.getNewLineText());
 
-        sb = new StrBuilder("A1-A2A3-A4");
-        sb.replace(A_NUMBER_MATCHER, "***", 0, sb.length(), -1);
-        assertEquals("***-******-***", sb.toString());
+        sb.setNewLineText("");
+        assertEquals("", sb.getNewLineText());
 
-        sb = new StrBuilder();
-        sb.replace(A_NUMBER_MATCHER, "***", 0, sb.length(), -1);
-        assertEquals("", sb.toString());
+        sb.setNewLineText((String) null);
+        assertNull(sb.getNewLineText());
     }
 
+    // -----------------------------------------------------------------------
     @Test
-    public void testReplace_StrMatcher_String_int_int_int_VaryReplace() {
-        StrBuilder sb = new StrBuilder("abcbccba");
-        sb.replace(StrMatcher.stringMatcher("cb"), "cb", 0, sb.length(), -1);
-        assertEquals("abcbccba", sb.toString());
+    public void testGetSetNullText() {
+        final StrBuilder sb = new StrBuilder();
+        assertNull(sb.getNullText());
 
-        sb = new StrBuilder("abcbccba");
-        sb.replace(StrMatcher.stringMatcher("cb"), "-", 0, sb.length(), -1);
-        assertEquals("ab-c-a", sb.toString());
+        sb.setNullText("null");
+        assertEquals("null", sb.getNullText());
 
-        sb = new StrBuilder("abcbccba");
-        sb.replace(StrMatcher.stringMatcher("cb"), "+++", 0, sb.length(), -1);
-        assertEquals("ab+++c+++a", sb.toString());
+        sb.setNullText("");
+        assertNull(sb.getNullText());
 
-        sb = new StrBuilder("abcbccba");
-        sb.replace(StrMatcher.stringMatcher("cb"), "", 0, sb.length(), -1);
-        assertEquals("abca", sb.toString());
+        sb.setNullText("NULL");
+        assertEquals("NULL", sb.getNullText());
 
-        sb = new StrBuilder("abcbccba");
-        sb.replace(StrMatcher.stringMatcher("cb"), null, 0, sb.length(), -1);
-        assertEquals("abca", sb.toString());
+        sb.setNullText((String) null);
+        assertNull(sb.getNullText());
     }
 
+    // -----------------------------------------------------------------------
     @Test
-    public void testReplace_StrMatcher_String_int_int_int_VaryStartIndex() {
-        StrBuilder sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, sb.length(), -1);
-        assertEquals("-x--y-", sb.toString());
+    public void testHashCode() {
+        final StrBuilder sb = new StrBuilder();
+        final int hc1a = sb.hashCode();
+        final int hc1b = sb.hashCode();
+        assertEquals(0, hc1a);
+        assertEquals(hc1a, hc1b);
 
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 1, sb.length(), -1);
-        assertEquals("aax--y-", sb.toString());
+        sb.append("abc");
+        final int hc2a = sb.hashCode();
+        final int hc2b = sb.hashCode();
+        assertTrue(hc2a != 0);
+        assertEquals(hc2a, hc2b);
+    }
 
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 2, sb.length(), -1);
-        assertEquals("aax--y-", sb.toString());
+    // -----------------------------------------------------------------------
+    @Test
+    public void testIndexOf_char() {
+        final StrBuilder sb = new StrBuilder("abab");
+        assertEquals(0, sb.indexOf('a'));
 
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 3, sb.length(), -1);
-        assertEquals("aax--y-", sb.toString());
+        // should work like String#indexOf
+        assertEquals("abab".indexOf('a'), sb.indexOf('a'));
 
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 4, sb.length(), -1);
-        assertEquals("aaxa-ay-", sb.toString());
+        assertEquals(1, sb.indexOf('b'));
+        assertEquals("abab".indexOf('b'), sb.indexOf('b'));
 
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 5, sb.length(), -1);
-        assertEquals("aaxaa-y-", sb.toString());
+        assertEquals(-1, sb.indexOf('z'));
+    }
 
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 6, sb.length(), -1);
-        assertEquals("aaxaaaay-", sb.toString());
+    @Test
+    public void testIndexOf_char_int() {
+        StrBuilder sb = new StrBuilder("abab");
+        assertEquals(0, sb.indexOf('a', -1));
+        assertEquals(0, sb.indexOf('a', 0));
+        assertEquals(2, sb.indexOf('a', 1));
+        assertEquals(-1, sb.indexOf('a', 4));
+        assertEquals(-1, sb.indexOf('a', 5));
 
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 7, sb.length(), -1);
-        assertEquals("aaxaaaay-", sb.toString());
+        // should work like String#indexOf
+        assertEquals("abab".indexOf('a', 1), sb.indexOf('a', 1));
 
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 8, sb.length(), -1);
-        assertEquals("aaxaaaay-", sb.toString());
+        assertEquals(3, sb.indexOf('b', 2));
+        assertEquals("abab".indexOf('b', 2), sb.indexOf('b', 2));
 
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 9, sb.length(), -1);
-        assertEquals("aaxaaaayaa", sb.toString());
+        assertEquals(-1, sb.indexOf('z', 2));
 
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 10, sb.length(), -1);
-        assertEquals("aaxaaaayaa", sb.toString());
+        sb = new StrBuilder("xyzabc");
+        assertEquals(2, sb.indexOf('z', 0));
+        assertEquals(-1, sb.indexOf('z', 3));
+    }
 
-        sb = new StrBuilder("aaxaaaayaa");
-        try {
-            sb.replace(StrMatcher.stringMatcher("aa"), "-", 11, sb.length(), -1);
-            fail("Exception expected!");
-        } catch (final IndexOutOfBoundsException ex) {
-            // expected
-        }
-        assertEquals("aaxaaaayaa", sb.toString());
+    // -----------------------------------------------------------------------
+    @Test
+    public void testIndexOf_String() {
+        final StrBuilder sb = new StrBuilder("abab");
 
-        sb = new StrBuilder("aaxaaaayaa");
-        try {
-            sb.replace(StrMatcher.stringMatcher("aa"), "-", -1, sb.length(), -1);
-            fail("Exception expected!");
-        } catch (final IndexOutOfBoundsException ex) {
-            // expected
-        }
-        assertEquals("aaxaaaayaa", sb.toString());
+        assertEquals(0, sb.indexOf("a"));
+        // should work like String#indexOf
+        assertEquals("abab".indexOf("a"), sb.indexOf("a"));
+
+        assertEquals(0, sb.indexOf("ab"));
+        // should work like String#indexOf
+        assertEquals("abab".indexOf("ab"), sb.indexOf("ab"));
+
+        assertEquals(1, sb.indexOf("b"));
+        assertEquals("abab".indexOf("b"), sb.indexOf("b"));
+
+        assertEquals(1, sb.indexOf("ba"));
+        assertEquals("abab".indexOf("ba"), sb.indexOf("ba"));
+
+        assertEquals(-1, sb.indexOf("z"));
+
+        assertEquals(-1, sb.indexOf((String) null));
     }
 
     @Test
-    public void testReplace_StrMatcher_String_int_int_int_VaryEndIndex() {
-        StrBuilder sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 0, -1);
-        assertEquals("aaxaaaayaa", sb.toString());
+    public void testIndexOf_String_int() {
+        StrBuilder sb = new StrBuilder("abab");
+        assertEquals(0, sb.indexOf("a", -1));
+        assertEquals(0, sb.indexOf("a", 0));
+        assertEquals(2, sb.indexOf("a", 1));
+        assertEquals(2, sb.indexOf("a", 2));
+        assertEquals(-1, sb.indexOf("a", 3));
+        assertEquals(-1, sb.indexOf("a", 4));
+        assertEquals(-1, sb.indexOf("a", 5));
 
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 2, -1);
-        assertEquals("-xaaaayaa", sb.toString());
+        assertEquals(-1, sb.indexOf("abcdef", 0));
+        assertEquals(0, sb.indexOf("", 0));
+        assertEquals(1, sb.indexOf("", 1));
 
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 3, -1);
-        assertEquals("-xaaaayaa", sb.toString());
+        // should work like String#indexOf
+        assertEquals("abab".indexOf("a", 1), sb.indexOf("a", 1));
 
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 4, -1);
-        assertEquals("-xaaaayaa", sb.toString());
+        assertEquals(2, sb.indexOf("ab", 1));
+        // should work like String#indexOf
+        assertEquals("abab".indexOf("ab", 1), sb.indexOf("ab", 1));
 
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 5, -1);
-        assertEquals("-x-aayaa", sb.toString());
+        assertEquals(3, sb.indexOf("b", 2));
+        assertEquals("abab".indexOf("b", 2), sb.indexOf("b", 2));
 
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 6, -1);
-        assertEquals("-x-aayaa", sb.toString());
+        assertEquals(1, sb.indexOf("ba", 1));
+        assertEquals("abab".indexOf("ba", 2), sb.indexOf("ba", 2));
 
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 7, -1);
-        assertEquals("-x--yaa", sb.toString());
+        assertEquals(-1, sb.indexOf("z", 2));
 
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 8, -1);
-        assertEquals("-x--yaa", sb.toString());
+        sb = new StrBuilder("xyzabc");
+        assertEquals(2, sb.indexOf("za", 0));
+        assertEquals(-1, sb.indexOf("za", 3));
 
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 9, -1);
-        assertEquals("-x--yaa", sb.toString());
+        assertEquals(-1, sb.indexOf((String) null, 2));
+    }
 
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, -1);
-        assertEquals("-x--y-", sb.toString());
+    // -----------------------------------------------------------------------
+    @Test
+    public void testIndexOf_StrMatcher() {
+        final StrBuilder sb = new StrBuilder();
+        assertEquals(-1, sb.indexOf((StrMatcher) null));
+        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('a')));
 
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 1000, -1);
-        assertEquals("-x--y-", sb.toString());
+        sb.append("ab bd");
+        assertEquals(0, sb.indexOf(StrMatcher.charMatcher('a')));
+        assertEquals(1, sb.indexOf(StrMatcher.charMatcher('b')));
+        assertEquals(2, sb.indexOf(StrMatcher.spaceMatcher()));
+        assertEquals(4, sb.indexOf(StrMatcher.charMatcher('d')));
+        assertEquals(-1, sb.indexOf(StrMatcher.noneMatcher()));
+        assertEquals(-1, sb.indexOf((StrMatcher) null));
 
-        sb = new StrBuilder("aaxaaaayaa");
-        try {
-            sb.replace(StrMatcher.stringMatcher("aa"), "-", 2, 1, -1);
-            fail("Exception expected!");
-        } catch (final IndexOutOfBoundsException ex) {
-            // expected
-        }
-        assertEquals("aaxaaaayaa", sb.toString());
+        sb.append(" A1 junction");
+        assertEquals(6, sb.indexOf(A_NUMBER_MATCHER));
     }
 
     @Test
-    public void testReplace_StrMatcher_String_int_int_int_VaryCount() {
-        StrBuilder sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, -1);
-        assertEquals("-x--y-", sb.toString());
-
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 0);
-        assertEquals("aaxaaaayaa", sb.toString());
+    public void testIndexOf_StrMatcher_int() {
+        final StrBuilder sb = new StrBuilder();
+        assertEquals(-1, sb.indexOf((StrMatcher) null, 2));
+        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('a'), 2));
+        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('a'), 0));
 
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 1);
-        assertEquals("-xaaaayaa", sb.toString());
+        sb.append("ab bd");
+        assertEquals(0, sb.indexOf(StrMatcher.charMatcher('a'), -2));
+        assertEquals(0, sb.indexOf(StrMatcher.charMatcher('a'), 0));
+        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('a'), 2));
+        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('a'), 20));
 
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 2);
-        assertEquals("-x-aayaa", sb.toString());
+        assertEquals(1, sb.indexOf(StrMatcher.charMatcher('b'), -1));
+        assertEquals(1, sb.indexOf(StrMatcher.charMatcher('b'), 0));
+        assertEquals(1, sb.indexOf(StrMatcher.charMatcher('b'), 1));
+        assertEquals(3, sb.indexOf(StrMatcher.charMatcher('b'), 2));
+        assertEquals(3, sb.indexOf(StrMatcher.charMatcher('b'), 3));
+        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('b'), 4));
+        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('b'), 5));
+        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('b'), 6));
 
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 3);
-        assertEquals("-x--yaa", sb.toString());
+        assertEquals(2, sb.indexOf(StrMatcher.spaceMatcher(), -2));
+        assertEquals(2, sb.indexOf(StrMatcher.spaceMatcher(), 0));
+        assertEquals(2, sb.indexOf(StrMatcher.spaceMatcher(), 2));
+        assertEquals(-1, sb.indexOf(StrMatcher.spaceMatcher(), 4));
+        assertEquals(-1, sb.indexOf(StrMatcher.spaceMatcher(), 20));
 
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 4);
-        assertEquals("-x--y-", sb.toString());
+        assertEquals(-1, sb.indexOf(StrMatcher.noneMatcher(), 0));
+        assertEquals(-1, sb.indexOf((StrMatcher) null, 0));
 
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 5);
-        assertEquals("-x--y-", sb.toString());
+        sb.append(" A1 junction with A2");
+        assertEquals(6, sb.indexOf(A_NUMBER_MATCHER, 5));
+        assertEquals(6, sb.indexOf(A_NUMBER_MATCHER, 6));
+        assertEquals(23, sb.indexOf(A_NUMBER_MATCHER, 7));
+        assertEquals(23, sb.indexOf(A_NUMBER_MATCHER, 22));
+        assertEquals(23, sb.indexOf(A_NUMBER_MATCHER, 23));
+        assertEquals(-1, sb.indexOf(A_NUMBER_MATCHER, 24));
     }
 
-    // -----------------------------------------------------------------------
     @Test
-    public void testReverse() {
-        final StrBuilder sb = new StrBuilder();
-        assertEquals("", sb.reverse().toString());
-
-        sb.clear().append(true);
-        assertEquals("eurt", sb.reverse().toString());
-        assertEquals("true", sb.reverse().toString());
+    public void testIndexOfLang294() {
+        final StrBuilder sb = new StrBuilder("onetwothree");
+        sb.deleteFirst("three");
+        assertEquals(-1, sb.indexOf("three"));
     }
 
-    // -----------------------------------------------------------------------
     @Test
-    public void testTrim() {
+    public void testIsEmpty() {
         final StrBuilder sb = new StrBuilder();
-        assertEquals("", sb.reverse().toString());
-
-        sb.clear().append(" \u0000 ");
-        assertEquals("", sb.trim().toString());
-
-        sb.clear().append(" \u0000 a b c");
-        assertEquals("a b c", sb.trim().toString());
+        assertTrue(sb.isEmpty());
 
-        sb.clear().append("a b c \u0000 ");
-        assertEquals("a b c", sb.trim().toString());
+        sb.append("Hello");
+        assertFalse(sb.isEmpty());
 
-        sb.clear().append(" \u0000 a b c \u0000 ");
-        assertEquals("a b c", sb.trim().toString());
+        sb.clear();
+        assertTrue(sb.isEmpty());
+    }
 
-        sb.clear().append("a b c");
-        assertEquals("a b c", sb.trim().toString());
+    // -----------------------------------------------------------------------
+    @Test
+    public void testLang294() {
+        final StrBuilder sb = new StrBuilder("\n%BLAH%\nDo more stuff\neven more stuff\n%BLAH%\n");
+        sb.deleteAll("\n%BLAH%");
+        assertEquals("\nDo more stuff\neven more stuff\n", sb.toString());
     }
 
     // -----------------------------------------------------------------------
     @Test
-    public void testStartsWith() {
-        final StrBuilder sb = new StrBuilder();
-        assertFalse(sb.startsWith("a"));
-        assertFalse(sb.startsWith(null));
-        assertTrue(sb.startsWith(""));
-        sb.append("abc");
-        assertTrue(sb.startsWith("a"));
-        assertTrue(sb.startsWith("ab"));
-        assertTrue(sb.startsWith("abc"));
-        assertFalse(sb.startsWith("cba"));
+    public void testLang295() {
+        final StrBuilder sb = new StrBuilder("onetwothree");
+        sb.deleteFirst("three");
+        assertFalse(sb.contains('h'), "The contains(char) method is looking beyond the end of the string");
+        assertEquals(-1, sb.indexOf('h'), "The indexOf(char) method is looking beyond the end of the string");
     }
 
     @Test
-    public void testEndsWith() {
+    public void testLang412Left() {
         final StrBuilder sb = new StrBuilder();
-        assertFalse(sb.endsWith("a"));
-        assertFalse(sb.endsWith("c"));
-        assertTrue(sb.endsWith(""));
-        assertFalse(sb.endsWith(null));
-        sb.append("abc");
-        assertTrue(sb.endsWith("c"));
-        assertTrue(sb.endsWith("bc"));
-        assertTrue(sb.endsWith("abc"));
-        assertFalse(sb.endsWith("cba"));
-        assertFalse(sb.endsWith("abcd"));
-        assertFalse(sb.endsWith(" abc"));
-        assertFalse(sb.endsWith("abc "));
+        sb.appendFixedWidthPadLeft(null, 10, '*');
+        assertEquals("**********", sb.toString(), "Failed to invoke appendFixedWidthPadLeft correctly");
     }
 
     // -----------------------------------------------------------------------
     @Test
-    public void testSubSequenceIntInt() {
-        final StrBuilder sb = new StrBuilder("hello goodbye");
-        // Start index is negative
-        assertThrows(IndexOutOfBoundsException.class, () -> sb.subSequence(-1, 5));
+    public void testLang412Right() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendFixedWidthPadRight(null, 10, '*');
+        assertEquals("**********", sb.toString(), "Failed to invoke appendFixedWidthPadRight correctly");
+    }
 
-        // End index is negative
-        assertThrows(IndexOutOfBoundsException.class, () -> sb.subSequence(2, -1));
+    @Test
+    public void testLastIndexOf_char() {
+        final StrBuilder sb = new StrBuilder("abab");
 
-        // End index greater than length()
-        assertThrows(IndexOutOfBoundsException.class, () -> sb.subSequence(2, sb.length() + 1));
-
-        // Start index greater then end index
-        assertThrows(IndexOutOfBoundsException.class, () -> sb.subSequence(3, 2));
-
-        // Normal cases
-        assertEquals("hello", sb.subSequence(0, 5));
-        assertEquals("hello goodbye".subSequence(0, 6), sb.subSequence(0, 6));
-        assertEquals("goodbye", sb.subSequence(6, 13));
-        assertEquals("hello goodbye".subSequence(6, 13), sb.subSequence(6, 13));
-    }
-
-    @Test
-    public void testSubstringInt() {
-        final StrBuilder sb = new StrBuilder("hello goodbye");
-        assertEquals("goodbye", sb.substring(6));
-        assertEquals("hello goodbye".substring(6), sb.substring(6));
-        assertEquals("hello goodbye", sb.substring(0));
-        assertEquals("hello goodbye".substring(0), sb.substring(0));
-        assertThrows(IndexOutOfBoundsException.class, () -> sb.substring(-1));
-        assertThrows(IndexOutOfBoundsException.class, () -> sb.substring(15));
-
-    }
-
-    @Test
-    public void testSubstringIntInt() {
-        final StrBuilder sb = new StrBuilder("hello goodbye");
-        assertEquals("hello", sb.substring(0, 5));
-        assertEquals("hello goodbye".substring(0, 6), sb.substring(0, 6));
-
-        assertEquals("goodbye", sb.substring(6, 13));
-        assertEquals("hello goodbye".substring(6, 13), sb.substring(6, 13));
-
-        assertEquals("goodbye", sb.substring(6, 20));
-
-        assertThrows(IndexOutOfBoundsException.class, () -> sb.substring(-1, 5));
-
-        assertThrows(IndexOutOfBoundsException.class, () -> sb.substring(15, 20));
-    }
-
-    // -----------------------------------------------------------------------
-    @Test
-    public void testMidString() {
-        final StrBuilder sb = new StrBuilder("hello goodbye hello");
-        assertEquals("goodbye", sb.midString(6, 7));
-        assertEquals("hello", sb.midString(0, 5));
-        assertEquals("hello", sb.midString(-5, 5));
-        assertEquals("", sb.midString(0, -1));
-        assertEquals("", sb.midString(20, 2));
-        assertEquals("hello", sb.midString(14, 22));
-    }
-
-    @Test
-    public void testRightString() {
-        final StrBuilder sb = new StrBuilder("left right");
-        assertEquals("right", sb.rightString(5));
-        assertEquals("", sb.rightString(0));
-        assertEquals("", sb.rightString(-5));
-        assertEquals("left right", sb.rightString(15));
-    }
-
-    @Test
-    public void testLeftString() {
-        final StrBuilder sb = new StrBuilder("left right");
-        assertEquals("left", sb.leftString(4));
-        assertEquals("", sb.leftString(0));
-        assertEquals("", sb.leftString(-5));
-        assertEquals("left right", sb.leftString(15));
-    }
-
-    // -----------------------------------------------------------------------
-    @Test
-    public void testContains_char() {
-        final StrBuilder sb = new StrBuilder("abcdefghijklmnopqrstuvwxyz");
-        assertTrue(sb.contains('a'));
-        assertTrue(sb.contains('o'));
-        assertTrue(sb.contains('z'));
-        assertFalse(sb.contains('1'));
-    }
-
-    @Test
-    public void testContains_String() {
-        final StrBuilder sb = new StrBuilder("abcdefghijklmnopqrstuvwxyz");
-        assertTrue(sb.contains("a"));
-        assertTrue(sb.contains("pq"));
-        assertTrue(sb.contains("z"));
-        assertFalse(sb.contains("zyx"));
-        assertFalse(sb.contains((String) null));
-    }
-
-    @Test
-    public void testContains_StrMatcher() {
-        StrBuilder sb = new StrBuilder("abcdefghijklmnopqrstuvwxyz");
-        assertTrue(sb.contains(StrMatcher.charMatcher('a')));
-        assertTrue(sb.contains(StrMatcher.stringMatcher("pq")));
-        assertTrue(sb.contains(StrMatcher.charMatcher('z')));
-        assertFalse(sb.contains(StrMatcher.stringMatcher("zy")));
-        assertFalse(sb.contains((StrMatcher) null));
-
-        sb = new StrBuilder();
-        assertFalse(sb.contains(A_NUMBER_MATCHER));
-        sb.append("B A1 C");
-        assertTrue(sb.contains(A_NUMBER_MATCHER));
-    }
-
-    // -----------------------------------------------------------------------
-    @Test
-    public void testIndexOf_char() {
-        final StrBuilder sb = new StrBuilder("abab");
-        assertEquals(0, sb.indexOf('a'));
-
-        // should work like String#indexOf
-        assertEquals("abab".indexOf('a'), sb.indexOf('a'));
-
-        assertEquals(1, sb.indexOf('b'));
-        assertEquals("abab".indexOf('b'), sb.indexOf('b'));
-
-        assertEquals(-1, sb.indexOf('z'));
-    }
-
-    @Test
-    public void testIndexOf_char_int() {
-        StrBuilder sb = new StrBuilder("abab");
-        assertEquals(0, sb.indexOf('a', -1));
-        assertEquals(0, sb.indexOf('a', 0));
-        assertEquals(2, sb.indexOf('a', 1));
-        assertEquals(-1, sb.indexOf('a', 4));
-        assertEquals(-1, sb.indexOf('a', 5));
-
-        // should work like String#indexOf
-        assertEquals("abab".indexOf('a', 1), sb.indexOf('a', 1));
-
-        assertEquals(3, sb.indexOf('b', 2));
-        assertEquals("abab".indexOf('b', 2), sb.indexOf('b', 2));
-
-        assertEquals(-1, sb.indexOf('z', 2));
-
-        sb = new StrBuilder("xyzabc");
-        assertEquals(2, sb.indexOf('z', 0));
-        assertEquals(-1, sb.indexOf('z', 3));
-    }
-
-    @Test
-    public void testLastIndexOf_char() {
-        final StrBuilder sb = new StrBuilder("abab");
-
-        assertEquals(2, sb.lastIndexOf('a'));
-        // should work like String#lastIndexOf
-        assertEquals("abab".lastIndexOf('a'), sb.lastIndexOf('a'));
+        assertEquals(2, sb.lastIndexOf('a'));
+        // should work like String#lastIndexOf
+        assertEquals("abab".lastIndexOf('a'), sb.lastIndexOf('a'));
 
         assertEquals(3, sb.lastIndexOf('b'));
         assertEquals("abab".lastIndexOf('b'), sb.lastIndexOf('b'));
@@ -1338,67 +1220,6 @@ public class StrBuilderTest {
         assertEquals(-1, sb.lastIndexOf('z', 1));
     }
 
-    // -----------------------------------------------------------------------
-    @Test
-    public void testIndexOf_String() {
-        final StrBuilder sb = new StrBuilder("abab");
-
-        assertEquals(0, sb.indexOf("a"));
-        // should work like String#indexOf
-        assertEquals("abab".indexOf("a"), sb.indexOf("a"));
-
-        assertEquals(0, sb.indexOf("ab"));
-        // should work like String#indexOf
-        assertEquals("abab".indexOf("ab"), sb.indexOf("ab"));
-
-        assertEquals(1, sb.indexOf("b"));
-        assertEquals("abab".indexOf("b"), sb.indexOf("b"));
-
-        assertEquals(1, sb.indexOf("ba"));
-        assertEquals("abab".indexOf("ba"), sb.indexOf("ba"));
-
-        assertEquals(-1, sb.indexOf("z"));
-
-        assertEquals(-1, sb.indexOf((String) null));
-    }
-
-    @Test
-    public void testIndexOf_String_int() {
-        StrBuilder sb = new StrBuilder("abab");
-        assertEquals(0, sb.indexOf("a", -1));
-        assertEquals(0, sb.indexOf("a", 0));
-        assertEquals(2, sb.indexOf("a", 1));
-        assertEquals(2, sb.indexOf("a", 2));
-        assertEquals(-1, sb.indexOf("a", 3));
-        assertEquals(-1, sb.indexOf("a", 4));
-        assertEquals(-1, sb.indexOf("a", 5));
-
-        assertEquals(-1, sb.indexOf("abcdef", 0));
-        assertEquals(0, sb.indexOf("", 0));
-        assertEquals(1, sb.indexOf("", 1));
-
-        // should work like String#indexOf
-        assertEquals("abab".indexOf("a", 1), sb.indexOf("a", 1));
-
-        assertEquals(2, sb.indexOf("ab", 1));
-        // should work like String#indexOf
-        assertEquals("abab".indexOf("ab", 1), sb.indexOf("ab", 1));
-
-        assertEquals(3, sb.indexOf("b", 2));
-        assertEquals("abab".indexOf("b", 2), sb.indexOf("b", 2));
-
-        assertEquals(1, sb.indexOf("ba", 1));
-        assertEquals("abab".indexOf("ba", 2), sb.indexOf("ba", 2));
-
-        assertEquals(-1, sb.indexOf("z", 2));
-
-        sb = new StrBuilder("xyzabc");
-        assertEquals(2, sb.indexOf("za", 0));
-        assertEquals(-1, sb.indexOf("za", 3));
-
-        assertEquals(-1, sb.indexOf((String) null, 2));
-    }
-
     @Test
     public void testLastIndexOf_String() {
         final StrBuilder sb = new StrBuilder("abab");
@@ -1459,96 +1280,37 @@ public class StrBuilderTest {
         assertEquals(-1, sb.lastIndexOf((String) null, 2));
     }
 
-    // -----------------------------------------------------------------------
     @Test
-    public void testIndexOf_StrMatcher() {
+    public void testLastIndexOf_StrMatcher() {
         final StrBuilder sb = new StrBuilder();
-        assertEquals(-1, sb.indexOf((StrMatcher) null));
-        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('a')));
+        assertEquals(-1, sb.lastIndexOf((StrMatcher) null));
+        assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('a')));
 
         sb.append("ab bd");
-        assertEquals(0, sb.indexOf(StrMatcher.charMatcher('a')));
-        assertEquals(1, sb.indexOf(StrMatcher.charMatcher('b')));
-        assertEquals(2, sb.indexOf(StrMatcher.spaceMatcher()));
-        assertEquals(4, sb.indexOf(StrMatcher.charMatcher('d')));
-        assertEquals(-1, sb.indexOf(StrMatcher.noneMatcher()));
-        assertEquals(-1, sb.indexOf((StrMatcher) null));
+        assertEquals(0, sb.lastIndexOf(StrMatcher.charMatcher('a')));
+        assertEquals(3, sb.lastIndexOf(StrMatcher.charMatcher('b')));
+        assertEquals(2, sb.lastIndexOf(StrMatcher.spaceMatcher()));
+        assertEquals(4, sb.lastIndexOf(StrMatcher.charMatcher('d')));
+        assertEquals(-1, sb.lastIndexOf(StrMatcher.noneMatcher()));
+        assertEquals(-1, sb.lastIndexOf((StrMatcher) null));
 
         sb.append(" A1 junction");
-        assertEquals(6, sb.indexOf(A_NUMBER_MATCHER));
+        assertEquals(6, sb.lastIndexOf(A_NUMBER_MATCHER));
     }
 
     @Test
-    public void testIndexOf_StrMatcher_int() {
+    public void testLastIndexOf_StrMatcher_int() {
         final StrBuilder sb = new StrBuilder();
-        assertEquals(-1, sb.indexOf((StrMatcher) null, 2));
-        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('a'), 2));
-        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('a'), 0));
+        assertEquals(-1, sb.lastIndexOf((StrMatcher) null, 2));
+        assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('a'), 2));
+        assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('a'), 0));
+        assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('a'), -1));
 
         sb.append("ab bd");
-        assertEquals(0, sb.indexOf(StrMatcher.charMatcher('a'), -2));
-        assertEquals(0, sb.indexOf(StrMatcher.charMatcher('a'), 0));
-        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('a'), 2));
-        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('a'), 20));
-
-        assertEquals(1, sb.indexOf(StrMatcher.charMatcher('b'), -1));
-        assertEquals(1, sb.indexOf(StrMatcher.charMatcher('b'), 0));
-        assertEquals(1, sb.indexOf(StrMatcher.charMatcher('b'), 1));
-        assertEquals(3, sb.indexOf(StrMatcher.charMatcher('b'), 2));
-        assertEquals(3, sb.indexOf(StrMatcher.charMatcher('b'), 3));
-        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('b'), 4));
-        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('b'), 5));
-        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('b'), 6));
-
-        assertEquals(2, sb.indexOf(StrMatcher.spaceMatcher(), -2));
-        assertEquals(2, sb.indexOf(StrMatcher.spaceMatcher(), 0));
-        assertEquals(2, sb.indexOf(StrMatcher.spaceMatcher(), 2));
-        assertEquals(-1, sb.indexOf(StrMatcher.spaceMatcher(), 4));
-        assertEquals(-1, sb.indexOf(StrMatcher.spaceMatcher(), 20));
-
-        assertEquals(-1, sb.indexOf(StrMatcher.noneMatcher(), 0));
-        assertEquals(-1, sb.indexOf((StrMatcher) null, 0));
-
-        sb.append(" A1 junction with A2");
-        assertEquals(6, sb.indexOf(A_NUMBER_MATCHER, 5));
-        assertEquals(6, sb.indexOf(A_NUMBER_MATCHER, 6));
-        assertEquals(23, sb.indexOf(A_NUMBER_MATCHER, 7));
-        assertEquals(23, sb.indexOf(A_NUMBER_MATCHER, 22));
-        assertEquals(23, sb.indexOf(A_NUMBER_MATCHER, 23));
-        assertEquals(-1, sb.indexOf(A_NUMBER_MATCHER, 24));
-    }
-
-    @Test
-    public void testLastIndexOf_StrMatcher() {
-        final StrBuilder sb = new StrBuilder();
-        assertEquals(-1, sb.lastIndexOf((StrMatcher) null));
-        assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('a')));
-
-        sb.append("ab bd");
-        assertEquals(0, sb.lastIndexOf(StrMatcher.charMatcher('a')));
-        assertEquals(3, sb.lastIndexOf(StrMatcher.charMatcher('b')));
-        assertEquals(2, sb.lastIndexOf(StrMatcher.spaceMatcher()));
-        assertEquals(4, sb.lastIndexOf(StrMatcher.charMatcher('d')));
-        assertEquals(-1, sb.lastIndexOf(StrMatcher.noneMatcher()));
-        assertEquals(-1, sb.lastIndexOf((StrMatcher) null));
-
-        sb.append(" A1 junction");
-        assertEquals(6, sb.lastIndexOf(A_NUMBER_MATCHER));
-    }
-
-    @Test
-    public void testLastIndexOf_StrMatcher_int() {
-        final StrBuilder sb = new StrBuilder();
-        assertEquals(-1, sb.lastIndexOf((StrMatcher) null, 2));
-        assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('a'), 2));
-        assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('a'), 0));
-        assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('a'), -1));
-
-        sb.append("ab bd");
-        assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('a'), -2));
-        assertEquals(0, sb.lastIndexOf(StrMatcher.charMatcher('a'), 0));
-        assertEquals(0, sb.lastIndexOf(StrMatcher.charMatcher('a'), 2));
-        assertEquals(0, sb.lastIndexOf(StrMatcher.charMatcher('a'), 20));
+        assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('a'), -2));
+        assertEquals(0, sb.lastIndexOf(StrMatcher.charMatcher('a'), 0));
+        assertEquals(0, sb.lastIndexOf(StrMatcher.charMatcher('a'), 2));
+        assertEquals(0, sb.lastIndexOf(StrMatcher.charMatcher('a'), 20));
 
         assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('b'), -1));
         assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('b'), 0));
@@ -1581,491 +1343,729 @@ public class StrBuilderTest {
         assertEquals(23, sb.lastIndexOf(A_NUMBER_MATCHER, 24));
     }
 
-    static final StrMatcher A_NUMBER_MATCHER = new StrMatcher() {
-
-        @Override
-        public int isMatch(final char[] buffer, int pos, final int bufferStart, final int bufferEnd) {
-            if (buffer[pos] == 'A') {
-                pos++;
-                if (pos < bufferEnd && buffer[pos] >= '0' && buffer[pos] <= '9') {
-                    return 2;
-                }
-            }
-            return 0;
-        }
-    };
+    @Test
+    public void testLeftString() {
+        final StrBuilder sb = new StrBuilder("left right");
+        assertEquals("left", sb.leftString(4));
+        assertEquals("", sb.leftString(0));
+        assertEquals("", sb.leftString(-5));
+        assertEquals("left right", sb.leftString(15));
+    }
 
     // -----------------------------------------------------------------------
     @Test
-    public void testAsTokenizer() throws Exception {
-        // from Javadoc
-        final StrBuilder b = new StrBuilder();
-        b.append("a b ");
-        final StrTokenizer t = b.asTokenizer();
+    public void testLength() {
+        final StrBuilder sb = new StrBuilder();
+        assertEquals(0, sb.length());
 
-        final String[] tokens1 = t.getTokenArray();
-        assertEquals(2, tokens1.length);
-        assertEquals("a", tokens1[0]);
-        assertEquals("b", tokens1[1]);
-        assertEquals(2, t.size());
+        sb.append("Hello");
+        assertEquals(5, sb.length());
+    }
 
-        b.append("c d ");
-        final String[] tokens2 = t.getTokenArray();
-        assertEquals(2, tokens2.length);
-        assertEquals("a", tokens2[0]);
-        assertEquals("b", tokens2[1]);
-        assertEquals(2, t.size());
-        assertEquals("a", t.next());
-        assertEquals("b", t.next());
+    // -----------------------------------------------------------------------
+    @Test
+    public void testMidString() {
+        final StrBuilder sb = new StrBuilder("hello goodbye hello");
+        assertEquals("goodbye", sb.midString(6, 7));
+        assertEquals("hello", sb.midString(0, 5));
+        assertEquals("hello", sb.midString(-5, 5));
+        assertEquals("", sb.midString(0, -1));
+        assertEquals("", sb.midString(20, 2));
+        assertEquals("hello", sb.midString(14, 22));
+    }
 
-        t.reset();
-        final String[] tokens3 = t.getTokenArray();
-        assertEquals(4, tokens3.length);
-        assertEquals("a", tokens3[0]);
-        assertEquals("b", tokens3[1]);
-        assertEquals("c", tokens3[2]);
-        assertEquals("d", tokens3[3]);
-        assertEquals(4, t.size());
-        assertEquals("a", t.next());
-        assertEquals("b", t.next());
-        assertEquals("c", t.next());
-        assertEquals("d", t.next());
+    @Test
+    public void testMinimizeCapacity() {
+        final StrBuilder sb = new StrBuilder();
+        sb.minimizeCapacity();
+        assertEquals(0, sb.capacity());
 
-        assertEquals("a b c d ", t.getContent());
+        sb.append("HelloWorld");
+        sb.minimizeCapacity();
+        assertEquals(10, sb.capacity());
     }
 
-    // -----------------------------------------------------------------------
     @Test
-    public void testAsReader() throws Exception {
-        final StrBuilder sb = new StrBuilder("some text");
-        try (Reader reader = sb.asReader()) {
-            assertTrue(reader.ready());
-            final char[] buf = new char[40];
-            assertEquals(9, reader.read(buf));
-            assertEquals("some text", new String(buf, 0, 9));
+    public void testReadFromCharBuffer() throws Exception {
+        String s = "";
+        for (int i = 0; i < 100; ++i) {
+            final StrBuilder sb = new StrBuilder();
+            final int len = sb.readFrom(CharBuffer.wrap(s));
 
-            assertEquals(-1, reader.read());
-            assertFalse(reader.ready());
-            assertEquals(0, reader.skip(2));
-            assertEquals(0, reader.skip(-1));
+            assertEquals(s.length(), len);
+            assertEquals(s, sb.toString());
 
-            assertTrue(reader.markSupported());
+            s += Integer.toString(i);
         }
-        try (Reader reader = sb.asReader()) {
-            assertEquals('s', reader.read());
-            reader.mark(-1);
-            char[] array = new char[3];
-            assertEquals(3, reader.read(array, 0, 3));
-            assertEquals('o', array[0]);
-            assertEquals('m', array[1]);
-            assertEquals('e', array[2]);
-            reader.reset();
-            assertEquals(1, reader.read(array, 1, 1));
-            assertEquals('o', array[0]);
-            assertEquals('o', array[1]);
-            assertEquals('e', array[2]);
-            assertEquals(2, reader.skip(2));
-            assertEquals(' ', reader.read());
+    }
 
-            assertTrue(reader.ready());
-            reader.close();
-            assertTrue(reader.ready());
-        }
-        try (Reader reader = sb.asReader()) {
-            char[] array = new char[3];
-            try {
-                reader.read(array, -1, 0);
-                fail("Exception expected!");
-            } catch (final IndexOutOfBoundsException ex) {
-                // expected
-            }
-            try {
-                reader.read(array, 0, -1);
-                fail("Exception expected!");
-            } catch (final IndexOutOfBoundsException ex) {
-                // expected
-            }
-            try {
-                reader.read(array, 100, 1);
-                fail("Exception expected!");
-            } catch (final IndexOutOfBoundsException ex) {
-                // expected
-            }
-            try {
-                reader.read(array, 0, 100);
-                fail("Exception expected!");
-            } catch (final IndexOutOfBoundsException ex) {
-                // expected
-            }
-            try {
-                reader.read(array, Integer.MAX_VALUE, Integer.MAX_VALUE);
-                fail("Exception expected!");
-            } catch (final IndexOutOfBoundsException ex) {
-                // expected
-            }
+    @Test
+    public void testReadFromCharBufferAppendsToEnd() throws Exception {
+        final StrBuilder sb = new StrBuilder("Test");
+        sb.readFrom(CharBuffer.wrap(" 123"));
+        assertEquals("Test 123", sb.toString());
+    }
 
-            assertEquals(0, reader.read(array, 0, 0));
-            assertEquals(0, array[0]);
-            assertEquals(0, array[1]);
-            assertEquals(0, array[2]);
+    @Test
+    public void testReadFromReadable() throws Exception {
+        String s = "";
+        for (int i = 0; i < 100; ++i) {
+            final StrBuilder sb = new StrBuilder();
+            final int len = sb.readFrom(new MockReadable(s));
 
-            reader.skip(9);
-            assertEquals(-1, reader.read(array, 0, 1));
+            assertEquals(s.length(), len);
+            assertEquals(s, sb.toString());
 
-            reader.reset();
-            array = new char[30];
-            assertEquals(9, reader.read(array, 0, 30));
+            s += Integer.toString(i);
         }
     }
 
+    @Test
+    public void testReadFromReadableAppendsToEnd() throws Exception {
+        final StrBuilder sb = new StrBuilder("Test");
+        sb.readFrom(new MockReadable(" 123"));
+        assertEquals("Test 123", sb.toString());
+    }
+
     // -----------------------------------------------------------------------
     @Test
-    public void testAsWriter() throws Exception {
-        final StrBuilder sb = new StrBuilder("base");
-        try (Writer writer = sb.asWriter()) {
+    public void testReadFromReader() throws Exception {
+        String s = "";
+        for (int i = 0; i < 100; ++i) {
+            final StrBuilder sb = new StrBuilder();
+            final int len = sb.readFrom(new StringReader(s));
 
-            writer.write('l');
-            assertEquals("basel", sb.toString());
+            assertEquals(s.length(), len);
+            assertEquals(s, sb.toString());
 
-            writer.write(new char[] {'i', 'n'});
-            assertEquals("baselin", sb.toString());
+            s += Integer.toString(i);
+        }
+    }
 
-            writer.write(new char[] {'n', 'e', 'r'}, 1, 2);
-            assertEquals("baseliner", sb.toString());
+    @Test
+    public void testReadFromReaderAppendsToEnd() throws Exception {
+        final StrBuilder sb = new StrBuilder("Test");
+        sb.readFrom(new StringReader(" 123"));
+        assertEquals("Test 123", sb.toString());
+    }
 
-            writer.write(" rout");
-            assertEquals("baseliner rout", sb.toString());
+    // -----------------------------------------------------------------------
+    @Test
+    public void testReplace_int_int_String() {
+        StrBuilder sb = new StrBuilder("abc");
+        sb.replace(0, 1, "d");
+        assertEquals("dbc", sb.toString());
+        sb.replace(0, 1, "aaa");
+        assertEquals("aaabc", sb.toString());
+        sb.replace(0, 3, "");
+        assertEquals("bc", sb.toString());
+        sb.replace(1, 2, (String) null);
+        assertEquals("b", sb.toString());
+        sb.replace(1, 1000, "text");
+        assertEquals("btext", sb.toString());
+        sb.replace(0, 1000, "text");
+        assertEquals("text", sb.toString());
 
-            writer.write("ping that server", 1, 3);
-            assertEquals("baseliner routing", sb.toString());
+        sb = new StrBuilder("atext");
+        sb.replace(1, 1, "ny");
+        assertEquals("anytext", sb.toString());
+        try {
+            sb.replace(2, 1, "anything");
+            fail("Expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
 
-            writer.flush(); // no effect
-            assertEquals("baseliner routing", sb.toString());
+        sb = new StrBuilder();
+        try {
+            sb.replace(1, 2, "anything");
+            fail("Expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+        try {
+            sb.replace(-1, 1, "anything");
+            fail("Expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+    }
 
-            writer.close(); // no effect
-            assertEquals("baseliner routing", sb.toString());
+    @Test
+    public void testReplace_StrMatcher_String_int_int_int_VaryCount() {
+        StrBuilder sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, -1);
+        assertEquals("-x--y-", sb.toString());
 
-            writer.write(" hi"); // works after close
-            assertEquals("baseliner routing hi", sb.toString());
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 0);
+        assertEquals("aaxaaaayaa", sb.toString());
 
-            sb.setLength(4); // mix and match
-            writer.write('d');
-            assertEquals("based", sb.toString());
-        }
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 1);
+        assertEquals("-xaaaayaa", sb.toString());
+
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 2);
+        assertEquals("-x-aayaa", sb.toString());
+
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 3);
+        assertEquals("-x--yaa", sb.toString());
+
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 4);
+        assertEquals("-x--y-", sb.toString());
+
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 5);
+        assertEquals("-x--y-", sb.toString());
     }
 
-    // -----------------------------------------------------------------------
     @Test
-    public void testEqualsIgnoreCase() {
-        final StrBuilder sb1 = new StrBuilder();
-        final StrBuilder sb2 = new StrBuilder();
-        assertTrue(sb1.equalsIgnoreCase(sb1));
-        assertTrue(sb1.equalsIgnoreCase(sb2));
-        assertTrue(sb2.equalsIgnoreCase(sb2));
+    public void testReplace_StrMatcher_String_int_int_int_VaryEndIndex() {
+        StrBuilder sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 0, -1);
+        assertEquals("aaxaaaayaa", sb.toString());
 
-        sb1.append("abc");
-        assertFalse(sb1.equalsIgnoreCase(sb2));
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 2, -1);
+        assertEquals("-xaaaayaa", sb.toString());
 
-        sb2.append("ABC");
-        assertTrue(sb1.equalsIgnoreCase(sb2));
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 3, -1);
+        assertEquals("-xaaaayaa", sb.toString());
 
-        sb2.clear().append("abc");
-        assertTrue(sb1.equalsIgnoreCase(sb2));
-        assertTrue(sb1.equalsIgnoreCase(sb1));
-        assertTrue(sb2.equalsIgnoreCase(sb2));
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 4, -1);
+        assertEquals("-xaaaayaa", sb.toString());
 
-        sb2.clear().append("aBc");
-        assertTrue(sb1.equalsIgnoreCase(sb2));
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 5, -1);
+        assertEquals("-x-aayaa", sb.toString());
+
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 6, -1);
+        assertEquals("-x-aayaa", sb.toString());
+
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 7, -1);
+        assertEquals("-x--yaa", sb.toString());
+
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 8, -1);
+        assertEquals("-x--yaa", sb.toString());
+
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 9, -1);
+        assertEquals("-x--yaa", sb.toString());
+
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, -1);
+        assertEquals("-x--y-", sb.toString());
+
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 1000, -1);
+        assertEquals("-x--y-", sb.toString());
+
+        sb = new StrBuilder("aaxaaaayaa");
+        try {
+            sb.replace(StrMatcher.stringMatcher("aa"), "-", 2, 1, -1);
+            fail("Exception expected!");
+        } catch (final IndexOutOfBoundsException ex) {
+            // expected
+        }
+        assertEquals("aaxaaaayaa", sb.toString());
     }
 
     // -----------------------------------------------------------------------
     @Test
-    public void testEquals() {
-        final StrBuilder sb1 = new StrBuilder();
-        final StrBuilder sb2 = new StrBuilder();
-        assertTrue(sb1.equals(sb2));
-        assertTrue(sb1.equals(sb1));
-        assertTrue(sb2.equals(sb2));
-        assertTrue(sb1.equals((Object) sb2));
+    public void testReplace_StrMatcher_String_int_int_int_VaryMatcher() {
+        StrBuilder sb = new StrBuilder("abcbccba");
+        sb.replace((StrMatcher) null, "x", 0, sb.length(), -1);
+        assertEquals("abcbccba", sb.toString());
 
-        sb1.append("abc");
-        assertFalse(sb1.equals(sb2));
-        assertFalse(sb1.equals((Object) sb2));
+        sb.replace(StrMatcher.charMatcher('a'), "x", 0, sb.length(), -1);
+        assertEquals("xbcbccbx", sb.toString());
 
-        sb2.append("ABC");
-        assertFalse(sb1.equals(sb2));
-        assertFalse(sb1.equals((Object) sb2));
+        sb.replace(StrMatcher.stringMatcher("cb"), "x", 0, sb.length(), -1);
+        assertEquals("xbxcxx", sb.toString());
 
-        sb2.clear().append("abc");
-        assertTrue(sb1.equals(sb2));
-        assertTrue(sb1.equals((Object) sb2));
+        sb = new StrBuilder("A1-A2A3-A4");
+        sb.replace(A_NUMBER_MATCHER, "***", 0, sb.length(), -1);
+        assertEquals("***-******-***", sb.toString());
 
-        assertFalse(sb1.equals(Integer.valueOf(1)));
-        assertFalse(sb1.equals("abc"));
+        sb = new StrBuilder();
+        sb.replace(A_NUMBER_MATCHER, "***", 0, sb.length(), -1);
+        assertEquals("", sb.toString());
     }
 
     @Test
-    public void test_LANG_1131_EqualsWithNullStrBuilder() throws Exception {
-        final StrBuilder sb = new StrBuilder();
-        final StrBuilder other = null;
-        assertFalse(sb.equals(other));
+    public void testReplace_StrMatcher_String_int_int_int_VaryReplace() {
+        StrBuilder sb = new StrBuilder("abcbccba");
+        sb.replace(StrMatcher.stringMatcher("cb"), "cb", 0, sb.length(), -1);
+        assertEquals("abcbccba", sb.toString());
+
+        sb = new StrBuilder("abcbccba");
+        sb.replace(StrMatcher.stringMatcher("cb"), "-", 0, sb.length(), -1);
+        assertEquals("ab-c-a", sb.toString());
+
+        sb = new StrBuilder("abcbccba");
+        sb.replace(StrMatcher.stringMatcher("cb"), "+++", 0, sb.length(), -1);
+        assertEquals("ab+++c+++a", sb.toString());
+
+        sb = new StrBuilder("abcbccba");
+        sb.replace(StrMatcher.stringMatcher("cb"), "", 0, sb.length(), -1);
+        assertEquals("abca", sb.toString());
+
+        sb = new StrBuilder("abcbccba");
+        sb.replace(StrMatcher.stringMatcher("cb"), null, 0, sb.length(), -1);
+        assertEquals("abca", sb.toString());
     }
 
-    // -----------------------------------------------------------------------
     @Test
-    public void testHashCode() {
-        final StrBuilder sb = new StrBuilder();
-        final int hc1a = sb.hashCode();
-        final int hc1b = sb.hashCode();
-        assertEquals(0, hc1a);
-        assertEquals(hc1a, hc1b);
+    public void testReplace_StrMatcher_String_int_int_int_VaryStartIndex() {
+        StrBuilder sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, sb.length(), -1);
+        assertEquals("-x--y-", sb.toString());
 
-        sb.append("abc");
-        final int hc2a = sb.hashCode();
-        final int hc2b = sb.hashCode();
-        assertTrue(hc2a != 0);
-        assertEquals(hc2a, hc2b);
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 1, sb.length(), -1);
+        assertEquals("aax--y-", sb.toString());
+
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 2, sb.length(), -1);
+        assertEquals("aax--y-", sb.toString());
+
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 3, sb.length(), -1);
+        assertEquals("aax--y-", sb.toString());
+
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 4, sb.length(), -1);
+        assertEquals("aaxa-ay-", sb.toString());
+
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 5, sb.length(), -1);
+        assertEquals("aaxaa-y-", sb.toString());
+
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 6, sb.length(), -1);
+        assertEquals("aaxaaaay-", sb.toString());
+
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 7, sb.length(), -1);
+        assertEquals("aaxaaaay-", sb.toString());
+
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 8, sb.length(), -1);
+        assertEquals("aaxaaaay-", sb.toString());
+
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 9, sb.length(), -1);
+        assertEquals("aaxaaaayaa", sb.toString());
+
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 10, sb.length(), -1);
+        assertEquals("aaxaaaayaa", sb.toString());
+
+        sb = new StrBuilder("aaxaaaayaa");
+        try {
+            sb.replace(StrMatcher.stringMatcher("aa"), "-", 11, sb.length(), -1);
+            fail("Exception expected!");
+        } catch (final IndexOutOfBoundsException ex) {
+            // expected
+        }
+        assertEquals("aaxaaaayaa", sb.toString());
+
+        sb = new StrBuilder("aaxaaaayaa");
+        try {
+            sb.replace(StrMatcher.stringMatcher("aa"), "-", -1, sb.length(), -1);
+            fail("Exception expected!");
+        } catch (final IndexOutOfBoundsException ex) {
+            // expected
+        }
+        assertEquals("aaxaaaayaa", sb.toString());
     }
 
     // -----------------------------------------------------------------------
     @Test
-    public void testToString() {
-        final StrBuilder sb = new StrBuilder("abc");
-        assertEquals("abc", sb.toString());
+    public void testReplaceAll_char_char() {
+        final StrBuilder sb = new StrBuilder("abcbccba");
+        sb.replaceAll('x', 'y');
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceAll('a', 'd');
+        assertEquals("dbcbccbd", sb.toString());
+        sb.replaceAll('b', 'e');
+        assertEquals("dececced", sb.toString());
+        sb.replaceAll('c', 'f');
+        assertEquals("defeffed", sb.toString());
+        sb.replaceAll('d', 'd');
+        assertEquals("defeffed", sb.toString());
     }
 
     // -----------------------------------------------------------------------
     @Test
-    public void testToStringBuffer() {
-        final StrBuilder sb = new StrBuilder();
-        assertEquals(new StringBuffer().toString(), sb.toStringBuffer().toString());
+    public void testReplaceAll_String_String() {
+        StrBuilder sb = new StrBuilder("abcbccba");
+        sb.replaceAll((String) null, null);
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceAll((String) null, "anything");
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceAll("", null);
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceAll("", "anything");
+        assertEquals("abcbccba", sb.toString());
 
-        sb.append("junit");
-        assertEquals(new StringBuffer("junit").toString(), sb.toStringBuffer().toString());
+        sb.replaceAll("x", "y");
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceAll("a", "d");
+        assertEquals("dbcbccbd", sb.toString());
+        sb.replaceAll("d", null);
+        assertEquals("bcbccb", sb.toString());
+        sb.replaceAll("cb", "-");
+        assertEquals("b-c-", sb.toString());
+
+        sb = new StrBuilder("abcba");
+        sb.replaceAll("b", "xbx");
+        assertEquals("axbxcxbxa", sb.toString());
+
+        sb = new StrBuilder("bb");
+        sb.replaceAll("b", "xbx");
+        assertEquals("xbxxbx", sb.toString());
     }
 
     // -----------------------------------------------------------------------
     @Test
-    public void testToStringBuilder() {
-        final StrBuilder sb = new StrBuilder();
-        assertEquals(new StringBuilder().toString(), sb.toStringBuilder().toString());
+    public void testReplaceAll_StrMatcher_String() {
+        StrBuilder sb = new StrBuilder("abcbccba");
+        sb.replaceAll((StrMatcher) null, null);
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceAll((StrMatcher) null, "anything");
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceAll(StrMatcher.noneMatcher(), null);
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceAll(StrMatcher.noneMatcher(), "anything");
+        assertEquals("abcbccba", sb.toString());
 
-        sb.append("junit");
-        assertEquals(new StringBuilder("junit").toString(), sb.toStringBuilder().toString());
+        sb.replaceAll(StrMatcher.charMatcher('x'), "y");
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceAll(StrMatcher.charMatcher('a'), "d");
+        assertEquals("dbcbccbd", sb.toString());
+        sb.replaceAll(StrMatcher.charMatcher('d'), null);
+        assertEquals("bcbccb", sb.toString());
+        sb.replaceAll(StrMatcher.stringMatcher("cb"), "-");
+        assertEquals("b-c-", sb.toString());
+
+        sb = new StrBuilder("abcba");
+        sb.replaceAll(StrMatcher.charMatcher('b'), "xbx");
+        assertEquals("axbxcxbxa", sb.toString());
+
+        sb = new StrBuilder("bb");
+        sb.replaceAll(StrMatcher.charMatcher('b'), "xbx");
+        assertEquals("xbxxbx", sb.toString());
+
+        sb = new StrBuilder("A1-A2A3-A4");
+        sb.replaceAll(A_NUMBER_MATCHER, "***");
+        assertEquals("***-******-***", sb.toString());
+
+        sb = new StrBuilder("Dear X, hello X.");
+        sb.replaceAll(StrMatcher.stringMatcher("X"), "012345678901234567");
+        assertEquals("Dear 012345678901234567, hello 012345678901234567.", sb.toString());
     }
 
     // -----------------------------------------------------------------------
     @Test
-    public void testLang294() {
-        final StrBuilder sb = new StrBuilder("\n%BLAH%\nDo more stuff\neven more stuff\n%BLAH%\n");
-        sb.deleteAll("\n%BLAH%");
-        assertEquals("\nDo more stuff\neven more stuff\n", sb.toString());
+    public void testReplaceFirst_char_char() {
+        final StrBuilder sb = new StrBuilder("abcbccba");
+        sb.replaceFirst('x', 'y');
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceFirst('a', 'd');
+        assertEquals("dbcbccba", sb.toString());
+        sb.replaceFirst('b', 'e');
+        assertEquals("decbccba", sb.toString());
+        sb.replaceFirst('c', 'f');
+        assertEquals("defbccba", sb.toString());
+        sb.replaceFirst('d', 'd');
+        assertEquals("defbccba", sb.toString());
     }
 
     @Test
-    public void testIndexOfLang294() {
-        final StrBuilder sb = new StrBuilder("onetwothree");
-        sb.deleteFirst("three");
-        assertEquals(-1, sb.indexOf("three"));
+    public void testReplaceFirst_String_String() {
+        StrBuilder sb = new StrBuilder("abcbccba");
+        sb.replaceFirst((String) null, null);
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceFirst((String) null, "anything");
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceFirst("", null);
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceFirst("", "anything");
+        assertEquals("abcbccba", sb.toString());
+
+        sb.replaceFirst("x", "y");
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceFirst("a", "d");
+        assertEquals("dbcbccba", sb.toString());
+        sb.replaceFirst("d", null);
+        assertEquals("bcbccba", sb.toString());
+        sb.replaceFirst("cb", "-");
+        assertEquals("b-ccba", sb.toString());
+
+        sb = new StrBuilder("abcba");
+        sb.replaceFirst("b", "xbx");
+        assertEquals("axbxcba", sb.toString());
+
+        sb = new StrBuilder("bb");
+        sb.replaceFirst("b", "xbx");
+        assertEquals("xbxb", sb.toString());
+    }
+
+    @Test
+    public void testReplaceFirst_StrMatcher_String() {
+        StrBuilder sb = new StrBuilder("abcbccba");
+        sb.replaceFirst((StrMatcher) null, null);
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceFirst((StrMatcher) null, "anything");
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceFirst(StrMatcher.noneMatcher(), null);
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceFirst(StrMatcher.noneMatcher(), "anything");
+        assertEquals("abcbccba", sb.toString());
+
+        sb.replaceFirst(StrMatcher.charMatcher('x'), "y");
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceFirst(StrMatcher.charMatcher('a'), "d");
+        assertEquals("dbcbccba", sb.toString());
+        sb.replaceFirst(StrMatcher.charMatcher('d'), null);
+        assertEquals("bcbccba", sb.toString());
+        sb.replaceFirst(StrMatcher.stringMatcher("cb"), "-");
+        assertEquals("b-ccba", sb.toString());
+
+        sb = new StrBuilder("abcba");
+        sb.replaceFirst(StrMatcher.charMatcher('b'), "xbx");
+        assertEquals("axbxcba", sb.toString());
+
+        sb = new StrBuilder("bb");
+        sb.replaceFirst(StrMatcher.charMatcher('b'), "xbx");
+        assertEquals("xbxb", sb.toString());
+
+        sb = new StrBuilder("A1-A2A3-A4");
+        sb.replaceFirst(A_NUMBER_MATCHER, "***");
+        assertEquals("***-A2A3-A4", sb.toString());
     }
 
     // -----------------------------------------------------------------------
     @Test
-    public void testLang295() {
-        final StrBuilder sb = new StrBuilder("onetwothree");
-        sb.deleteFirst("three");
-        assertFalse(sb.contains('h'), "The contains(char) method is looking beyond the end of the string");
-        assertEquals(-1, sb.indexOf('h'), "The indexOf(char) method is looking beyond the end of the string");
+    public void testReverse() {
+        final StrBuilder sb = new StrBuilder();
+        assertEquals("", sb.reverse().toString());
+
+        sb.clear().append(true);
+        assertEquals("eurt", sb.reverse().toString());
+        assertEquals("true", sb.reverse().toString());
+    }
+
+    @Test
+    public void testRightString() {
+        final StrBuilder sb = new StrBuilder("left right");
+        assertEquals("right", sb.rightString(5));
+        assertEquals("", sb.rightString(0));
+        assertEquals("", sb.rightString(-5));
+        assertEquals("left right", sb.rightString(15));
     }
 
     // -----------------------------------------------------------------------
     @Test
-    public void testLang412Right() {
+    public void testSetCharAt() {
         final StrBuilder sb = new StrBuilder();
-        sb.appendFixedWidthPadRight(null, 10, '*');
-        assertEquals("**********", sb.toString(), "Failed to invoke appendFixedWidthPadRight correctly");
+        assertThrows(IndexOutOfBoundsException.class, () -> sb.setCharAt(0, 'f'));
+        assertThrows(IndexOutOfBoundsException.class, () -> sb.setCharAt(-1, 'f'));
+        sb.append("foo");
+        sb.setCharAt(0, 'b');
+        sb.setCharAt(1, 'a');
+        sb.setCharAt(2, 'r');
+        assertThrows(IndexOutOfBoundsException.class, () -> sb.setCharAt(3, '!'));
+        assertEquals("bar", sb.toString());
     }
 
     @Test
-    public void testLang412Left() {
+    public void testSetLength() {
         final StrBuilder sb = new StrBuilder();
-        sb.appendFixedWidthPadLeft(null, 10, '*');
-        assertEquals("**********", sb.toString(), "Failed to invoke appendFixedWidthPadLeft correctly");
-    }
+        sb.append("Hello");
+        sb.setLength(2); // shorten
+        assertEquals("He", sb.toString());
+        sb.setLength(2); // no change
+        assertEquals("He", sb.toString());
+        sb.setLength(3); // lengthen
+        assertEquals("He\0", sb.toString());
 
-    @Test
-    public void testAsBuilder() {
-        final StrBuilder sb = new StrBuilder().appendAll("Lorem", " ", "ipsum", " ", "dolor");
-        assertEquals(sb.toString(), sb.build());
+        assertThrows(IndexOutOfBoundsException.class, () -> sb.setLength(-1));
     }
 
     // -----------------------------------------------------------------------
     @Test
-    public void testAppendCharBuffer() {
-        final StrBuilder sb1 = new StrBuilder();
-        final CharBuffer buf = CharBuffer.allocate(10);
-        buf.append("0123456789");
-        buf.flip();
-        sb1.append(buf);
-        assertEquals("0123456789", sb1.toString());
+    public void testSize() {
+        final StrBuilder sb = new StrBuilder();
+        assertEquals(0, sb.size());
 
-        final StrBuilder sb2 = new StrBuilder();
-        sb2.append(buf, 1, 8);
-        assertEquals("12345678", sb2.toString());
+        sb.append("Hello");
+        assertEquals(5, sb.size());
     }
 
     // -----------------------------------------------------------------------
     @Test
-    public void testAppendToWriter() throws Exception {
-        final StrBuilder sb = new StrBuilder("1234567890");
-        final StringWriter writer = new StringWriter();
-        writer.append("Test ");
-
-        sb.appendTo(writer);
-
-        assertEquals("Test 1234567890", writer.toString());
+    public void testStartsWith() {
+        final StrBuilder sb = new StrBuilder();
+        assertFalse(sb.startsWith("a"));
+        assertFalse(sb.startsWith(null));
+        assertTrue(sb.startsWith(""));
+        sb.append("abc");
+        assertTrue(sb.startsWith("a"));
+        assertTrue(sb.startsWith("ab"));
+        assertTrue(sb.startsWith("abc"));
+        assertFalse(sb.startsWith("cba"));
     }
 
+    // -----------------------------------------------------------------------
     @Test
-    public void testAppendToStringBuilder() throws Exception {
-        final StrBuilder sb = new StrBuilder("1234567890");
-        final StringBuilder builder = new StringBuilder("Test ");
+    public void testSubSequenceIntInt() {
+        final StrBuilder sb = new StrBuilder("hello goodbye");
+        // Start index is negative
+        assertThrows(IndexOutOfBoundsException.class, () -> sb.subSequence(-1, 5));
 
-        sb.appendTo(builder);
+        // End index is negative
+        assertThrows(IndexOutOfBoundsException.class, () -> sb.subSequence(2, -1));
 
-        assertEquals("Test 1234567890", builder.toString());
+        // End index greater than length()
+        assertThrows(IndexOutOfBoundsException.class, () -> sb.subSequence(2, sb.length() + 1));
+
+        // Start index greater then end index
+        assertThrows(IndexOutOfBoundsException.class, () -> sb.subSequence(3, 2));
+
+        // Normal cases
+        assertEquals("hello", sb.subSequence(0, 5));
+        assertEquals("hello goodbye".subSequence(0, 6), sb.subSequence(0, 6));
+        assertEquals("goodbye", sb.subSequence(6, 13));
+        assertEquals("hello goodbye".subSequence(6, 13), sb.subSequence(6, 13));
     }
 
     @Test
-    public void testAppendToStringBuffer() throws Exception {
-        final StrBuilder sb = new StrBuilder("1234567890");
-        final StringBuffer buffer = new StringBuffer("Test ");
-
-        sb.appendTo(buffer);
+    public void testSubstringInt() {
+        final StrBuilder sb = new StrBuilder("hello goodbye");
+        assertEquals("goodbye", sb.substring(6));
+        assertEquals("hello goodbye".substring(6), sb.substring(6));
+        assertEquals("hello goodbye", sb.substring(0));
+        assertEquals("hello goodbye".substring(0), sb.substring(0));
+        assertThrows(IndexOutOfBoundsException.class, () -> sb.substring(-1));
+        assertThrows(IndexOutOfBoundsException.class, () -> sb.substring(15));
 
-        assertEquals("Test 1234567890", buffer.toString());
     }
 
     @Test
-    public void testAppendToCharBuffer() throws Exception {
-        final StrBuilder sb = new StrBuilder("1234567890");
-        final String text = "Test ";
-        final CharBuffer buffer = CharBuffer.allocate(sb.size() + text.length());
-        buffer.put(text);
+    public void testSubstringIntInt() {
+        final StrBuilder sb = new StrBuilder("hello goodbye");
+        assertEquals("hello", sb.substring(0, 5));
+        assertEquals("hello goodbye".substring(0, 6), sb.substring(0, 6));
 
-        sb.appendTo(buffer);
+        assertEquals("goodbye", sb.substring(6, 13));
+        assertEquals("hello goodbye".substring(6, 13), sb.substring(6, 13));
 
-        buffer.flip();
-        assertEquals("Test 1234567890", buffer.toString());
-    }
+        assertEquals("goodbye", sb.substring(6, 20));
 
-    @Test
-    public void testAppendCharBufferNull() throws Exception {
-        final StrBuilder sb = new StrBuilder("1234567890");
-        final CharBuffer buffer = null;
-        sb.append(buffer);
-        assertEquals("1234567890", sb.toString());
+        assertThrows(IndexOutOfBoundsException.class, () -> sb.substring(-1, 5));
 
-        final StrBuilder sb1 = new StrBuilder("1234567890");
-        final CharBuffer buffer1 = null;
-        sb.append(buffer1, 0, 0);
-        assertEquals("1234567890", sb1.toString());
+        assertThrows(IndexOutOfBoundsException.class, () -> sb.substring(15, 20));
     }
 
+    // -----------------------------------------------------------------------
     @Test
-    public void testAppendCharBufferException() throws Exception {
-        final StrBuilder sb = new StrBuilder("1234567890");
-        final String text = "Test";
-        final CharBuffer buffer = CharBuffer.allocate(sb.size() + text.length());
-        buffer.put(text);
-        buffer.flip();
-        try {
-            sb.append(buffer, -1, 12);
-        } catch (final StringIndexOutOfBoundsException e) {
-            assertEquals("startIndex must be valid", e.getMessage());
-        }
+    public void testToCharArray() {
+        final StrBuilder sb = new StrBuilder();
+        assertEquals(0, sb.toCharArray().length);
 
-        try {
-            sb.append(buffer, 0, -1);
-        } catch (final StringIndexOutOfBoundsException e) {
-            assertEquals("length must be valid", e.getMessage());
-        }
+        char[] a = sb.toCharArray();
+        assertNotNull(a, "toCharArray() result is null");
+        assertEquals(0, a.length, "toCharArray() result is too large");
 
-        sb.append(buffer);
-        assertEquals("1234567890Test", sb.toString());
+        sb.append("junit");
+        a = sb.toCharArray();
+        assertEquals(5, a.length, "toCharArray() result incorrect length");
+        assertTrue(Arrays.equals("junit".toCharArray(), a), "toCharArray() result does not match");
     }
 
     @Test
-    public void testAppendCharSequence() {
-        final CharSequence obj0 = null;
-        final CharSequence obj1 = new StrBuilder("test1");
-        final CharSequence obj2 = new StringBuilder("test2");
-        final CharSequence obj3 = new StringBuffer("test3");
-        final CharBuffer obj4 = CharBuffer.wrap("test4".toCharArray());
+    public void testToCharArrayIntInt() {
+        final StrBuilder sb = new StrBuilder();
+        assertEquals(0, sb.toCharArray(0, 0).length);
 
-        final StrBuilder sb0 = new StrBuilder();
-        assertEquals("", sb0.append(obj0).toString());
+        sb.append("junit");
+        char[] a = sb.toCharArray(0, 20); // too large test
+        assertEquals(5, a.length, "toCharArray(int,int) result incorrect length");
+        assertTrue(Arrays.equals("junit".toCharArray(), a), "toCharArray(int,int) result does not match");
 
-        final StrBuilder sb1 = new StrBuilder();
-        assertEquals("test1", sb1.append(obj1).toString());
+        a = sb.toCharArray(0, 4);
+        assertEquals(4, a.length, "toCharArray(int,int) result incorrect length");
+        assertTrue(Arrays.equals("juni".toCharArray(), a), "toCharArray(int,int) result does not match");
 
-        final StrBuilder sb2 = new StrBuilder();
-        assertEquals("test2", sb2.append(obj2).toString());
+        a = sb.toCharArray(0, 4);
+        assertEquals(4, a.length, "toCharArray(int,int) result incorrect length");
+        assertTrue(Arrays.equals("juni".toCharArray(), a), "toCharArray(int,int) result does not match");
 
-        final StrBuilder sb3 = new StrBuilder();
-        assertEquals("test3", sb3.append(obj3).toString());
+        a = sb.toCharArray(0, 1);
+        assertNotNull(a, "toCharArray(int,int) result is null");
 
-        final StrBuilder sb4 = new StrBuilder();
-        assertEquals("test4", sb4.append(obj4).toString());
+        assertThrows(IndexOutOfBoundsException.class, () -> sb.toCharArray(-1, 5));
 
-        final StrBuilder sb5 = new StrBuilder();
-        assertEquals("", sb5.append(obj0, 0, 0).toString());
+        assertThrows(IndexOutOfBoundsException.class, () -> sb.toCharArray(6, 5));
     }
 
+    // -----------------------------------------------------------------------
     @Test
-    public void testAppendStringBuilderNull() {
-        final StrBuilder sb1 = new StrBuilder();
-        final StringBuilder b = null;
-        assertEquals("", sb1.append(b).toString());
-
-        final StrBuilder sb2 = new StrBuilder();
-        assertEquals("", sb2.append(b, 0, 0).toString());
+    public void testToString() {
+        final StrBuilder sb = new StrBuilder("abc");
+        assertEquals("abc", sb.toString());
     }
 
+    // -----------------------------------------------------------------------
     @Test
-    public void testAppendln() {
-        final StrBuilder sb1 = new StrBuilder();
-        final char ch = 'c';
-        assertEquals("c" + System.lineSeparator(), sb1.appendln(ch).toString());
+    public void testToStringBuffer() {
+        final StrBuilder sb = new StrBuilder();
+        assertEquals(new StringBuffer().toString(), sb.toStringBuffer().toString());
+
+        sb.append("junit");
+        assertEquals(new StringBuffer("junit").toString(), sb.toStringBuffer().toString());
     }
 
+    // -----------------------------------------------------------------------
     @Test
-    public void testAppendTakingTwoIntsWithZeroThrowsStringIndexOutOfBoundsException() {
-        assertThatExceptionOfType(StringIndexOutOfBoundsException.class).isThrownBy(() -> {
-            final Charset charset = Charset.defaultCharset();
-            final ByteBuffer byteBuffer = charset.encode("end < start");
-            final CharBuffer charBuffer = charset.decode(byteBuffer);
+    public void testToStringBuilder() {
+        final StrBuilder sb = new StrBuilder();
+        assertEquals(new StringBuilder().toString(), sb.toStringBuilder().toString());
 
-            new StrBuilder(630).append(charBuffer, 0, 630);
-        });
+        sb.append("junit");
+        assertEquals(new StringBuilder("junit").toString(), sb.toStringBuilder().toString());
     }
 
+    // -----------------------------------------------------------------------
     @Test
-    public void testAppendTakingTwoIntsWithIndexOutOfBoundsThrowsStringIndexOutOfBoundsExceptionTwo() {
-        assertThatExceptionOfType(StringIndexOutOfBoundsException.class).isThrownBy(() -> {
-            final Charset charset = Charset.defaultCharset();
-            final ByteBuffer byteBuffer = charset.encode("asdf");
-            final CharBuffer charBuffer = charset.decode(byteBuffer);
+    public void testTrim() {
+        final StrBuilder sb = new StrBuilder();
+        assertEquals("", sb.reverse().toString());
 
-            new StrBuilder().append(charBuffer, 933, 654);
-        });
-    }
+        sb.clear().append(" \u0000 ");
+        assertEquals("", sb.trim().toString());
 
-    @Test
-    public void testDeleteCharAtWithNegative() {
-        assertThatExceptionOfType(StringIndexOutOfBoundsException.class).isThrownBy(() -> {
-            new StrBuilder().deleteCharAt((-1258));
-        });
+        sb.clear().append(" \u0000 a b c");
+        assertEquals("a b c", sb.trim().toString());
+
+        sb.clear().append("a b c \u0000 ");
+        assertEquals("a b c", sb.trim().toString());
+
+        sb.clear().append(" \u0000 a b c \u0000 ");
+        assertEquals("a b c", sb.trim().toString());
+
+        sb.clear().append("a b c");
+        assertEquals("a b c", sb.trim().toString());
     }
 
 }
diff --git a/src/test/java/org/apache/commons/text/StrLookupTest.java b/src/test/java/org/apache/commons/text/StrLookupTest.java
index be0d0f5..c665378 100644
--- a/src/test/java/org/apache/commons/text/StrLookupTest.java
+++ b/src/test/java/org/apache/commons/text/StrLookupTest.java
@@ -35,6 +35,26 @@ import org.junit.jupiter.api.Test;
 @Deprecated
 public class StrLookupTest  {
 
+    @Test
+    public void testMapLookup() {
+        final Map<String, Object> map = new HashMap<>();
+        map.put("key", "value");
+        map.put("number", 2);
+        assertEquals("value", StrLookup.mapLookup(map).lookup("key"));
+        assertEquals("2", StrLookup.mapLookup(map).lookup("number"));
+        assertNull(StrLookup.mapLookup(map).lookup(null));
+        assertNull(StrLookup.mapLookup(map).lookup(""));
+        assertNull(StrLookup.mapLookup(map).lookup("other"));
+    }
+
+    @Test
+    public void testMapLookup_nullMap() {
+        final Map<String, ?> map = null;
+        assertNull(StrLookup.mapLookup(map).lookup(null));
+        assertNull(StrLookup.mapLookup(map).lookup(""));
+        assertNull(StrLookup.mapLookup(map).lookup("any"));
+    }
+
     //-----------------------------------------------------------------------
     @Test
     public void testNoneLookup() {
@@ -44,6 +64,24 @@ public class StrLookupTest  {
     }
 
     @Test
+    public void testResourceBundleLookup() {
+        final ResourceBundle map = ResourceBundle.getBundle("org.example.testResourceBundleLookup");
+        assertEquals("value", StrLookup.resourceBundleLookup(map).lookup("key"));
+        assertEquals("2", StrLookup.resourceBundleLookup(map).lookup("number"));
+        assertNull(StrLookup.resourceBundleLookup(map).lookup(null));
+        assertNull(StrLookup.resourceBundleLookup(map).lookup(""));
+        assertNull(StrLookup.resourceBundleLookup(map).lookup("other"));
+    }
+
+    @Test
+    public void testResourceBundleLookup_nullMap() {
+        final ResourceBundle resourceBundle = null;
+        assertNull(StrLookup.resourceBundleLookup(resourceBundle).lookup(null));
+        assertNull(StrLookup.resourceBundleLookup(resourceBundle).lookup(""));
+        assertNull(StrLookup.resourceBundleLookup(resourceBundle).lookup("any"));
+    }
+
+    @Test
     public void testSystemProperiesLookup() {
         assertEquals(System.getProperty("os.name"), StrLookup.systemPropertiesLookup().lookup("os.name"));
         assertNull(StrLookup.systemPropertiesLookup().lookup(""));
@@ -92,43 +130,5 @@ public class StrLookupTest  {
         }
     }
 
-    @Test
-    public void testMapLookup() {
-        final Map<String, Object> map = new HashMap<>();
-        map.put("key", "value");
-        map.put("number", 2);
-        assertEquals("value", StrLookup.mapLookup(map).lookup("key"));
-        assertEquals("2", StrLookup.mapLookup(map).lookup("number"));
-        assertNull(StrLookup.mapLookup(map).lookup(null));
-        assertNull(StrLookup.mapLookup(map).lookup(""));
-        assertNull(StrLookup.mapLookup(map).lookup("other"));
-    }
-
-    @Test
-    public void testResourceBundleLookup() {
-        final ResourceBundle map = ResourceBundle.getBundle("org.example.testResourceBundleLookup");
-        assertEquals("value", StrLookup.resourceBundleLookup(map).lookup("key"));
-        assertEquals("2", StrLookup.resourceBundleLookup(map).lookup("number"));
-        assertNull(StrLookup.resourceBundleLookup(map).lookup(null));
-        assertNull(StrLookup.resourceBundleLookup(map).lookup(""));
-        assertNull(StrLookup.resourceBundleLookup(map).lookup("other"));
-    }
-
-    @Test
-    public void testResourceBundleLookup_nullMap() {
-        final ResourceBundle resourceBundle = null;
-        assertNull(StrLookup.resourceBundleLookup(resourceBundle).lookup(null));
-        assertNull(StrLookup.resourceBundleLookup(resourceBundle).lookup(""));
-        assertNull(StrLookup.resourceBundleLookup(resourceBundle).lookup("any"));
-    }
-
-    @Test
-    public void testMapLookup_nullMap() {
-        final Map<String, ?> map = null;
-        assertNull(StrLookup.mapLookup(map).lookup(null));
-        assertNull(StrLookup.mapLookup(map).lookup(""));
-        assertNull(StrLookup.mapLookup(map).lookup("any"));
-    }
-
 
 }
diff --git a/src/test/java/org/apache/commons/text/StrMatcherTest.java b/src/test/java/org/apache/commons/text/StrMatcherTest.java
index 661c5d7..c51d1bb 100644
--- a/src/test/java/org/apache/commons/text/StrMatcherTest.java
+++ b/src/test/java/org/apache/commons/text/StrMatcherTest.java
@@ -35,74 +35,54 @@ public class StrMatcherTest  {
 
     //-----------------------------------------------------------------------
     @Test
-    public void testCommaMatcher() {
-        final StrMatcher matcher = StrMatcher.commaMatcher();
-        assertThat(StrMatcher.commaMatcher()).isSameAs(matcher);
-        assertThat(matcher.isMatch(BUFFER1, 0)).isEqualTo(0);
-        assertThat(matcher.isMatch(BUFFER1, 1)).isEqualTo(1);
-        assertThat(matcher.isMatch(BUFFER1, 2)).isEqualTo(0);
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testTabMatcher() {
-        final StrMatcher matcher = StrMatcher.tabMatcher();
-        assertThat(StrMatcher.tabMatcher()).isSameAs(matcher);
-        assertThat(matcher.isMatch(BUFFER1, 2)).isEqualTo(0);
-        assertThat(matcher.isMatch(BUFFER1, 3)).isEqualTo(1);
-        assertThat(matcher.isMatch(BUFFER1, 4)).isEqualTo(0);
+    public void testCharMatcher_char() {
+        final StrMatcher matcher = StrMatcher.charMatcher('c');
+        assertThat(matcher.isMatch(BUFFER2, 0)).isEqualTo(0);
+        assertThat(matcher.isMatch(BUFFER2, 1)).isEqualTo(0);
+        assertThat(matcher.isMatch(BUFFER2, 2)).isEqualTo(1);
+        assertThat(matcher.isMatch(BUFFER2, 3)).isEqualTo(0);
+        assertThat(matcher.isMatch(BUFFER2, 4)).isEqualTo(0);
+        assertThat(matcher.isMatch(BUFFER2, 5)).isEqualTo(0);
     }
 
     //-----------------------------------------------------------------------
     @Test
-    public void testSpaceMatcher() {
-        final StrMatcher matcher = StrMatcher.spaceMatcher();
-        assertThat(StrMatcher.spaceMatcher()).isSameAs(matcher);
-        assertThat(matcher.isMatch(BUFFER1, 4)).isEqualTo(0);
-        assertThat(matcher.isMatch(BUFFER1, 5)).isEqualTo(1);
-        assertThat(matcher.isMatch(BUFFER1, 6)).isEqualTo(0);
+    public void testCharSetMatcher_charArray() {
+        final StrMatcher matcher = StrMatcher.charSetMatcher("ace".toCharArray());
+        assertThat(matcher.isMatch(BUFFER2, 0)).isEqualTo(1);
+        assertThat(matcher.isMatch(BUFFER2, 1)).isEqualTo(0);
+        assertThat(matcher.isMatch(BUFFER2, 2)).isEqualTo(1);
+        assertThat(matcher.isMatch(BUFFER2, 3)).isEqualTo(0);
+        assertThat(matcher.isMatch(BUFFER2, 4)).isEqualTo(1);
+        assertThat(matcher.isMatch(BUFFER2, 5)).isEqualTo(0);
+        assertThat(StrMatcher.charSetMatcher()).isSameAs(StrMatcher.noneMatcher());
+        assertThat(StrMatcher.charSetMatcher((char[]) null)).isSameAs(StrMatcher.noneMatcher());
+        assertThat(StrMatcher.charSetMatcher("a".toCharArray()) instanceof StrMatcher.CharMatcher).isTrue();
     }
 
     //-----------------------------------------------------------------------
     @Test
-    public void testSplitMatcher() {
-        final StrMatcher matcher = StrMatcher.splitMatcher();
-        assertThat(StrMatcher.splitMatcher()).isSameAs(matcher);
-        assertThat(matcher.isMatch(BUFFER1, 2)).isEqualTo(0);
-        assertThat(matcher.isMatch(BUFFER1, 3)).isEqualTo(1);
-        assertThat(matcher.isMatch(BUFFER1, 4)).isEqualTo(0);
-        assertThat(matcher.isMatch(BUFFER1, 5)).isEqualTo(1);
-        assertThat(matcher.isMatch(BUFFER1, 6)).isEqualTo(0);
-        assertThat(matcher.isMatch(BUFFER1, 7)).isEqualTo(1);
-        assertThat(matcher.isMatch(BUFFER1, 8)).isEqualTo(1);
-        assertThat(matcher.isMatch(BUFFER1, 9)).isEqualTo(1);
-        assertThat(matcher.isMatch(BUFFER1, 10)).isEqualTo(0);
+    public void testCharSetMatcher_String() {
+        final StrMatcher matcher = StrMatcher.charSetMatcher("ace");
+        assertThat(matcher.isMatch(BUFFER2, 0)).isEqualTo(1);
+        assertThat(matcher.isMatch(BUFFER2, 1)).isEqualTo(0);
+        assertThat(matcher.isMatch(BUFFER2, 2)).isEqualTo(1);
+        assertThat(matcher.isMatch(BUFFER2, 3)).isEqualTo(0);
+        assertThat(matcher.isMatch(BUFFER2, 4)).isEqualTo(1);
+        assertThat(matcher.isMatch(BUFFER2, 5)).isEqualTo(0);
+        assertThat(StrMatcher.charSetMatcher("")).isSameAs(StrMatcher.noneMatcher());
+        assertThat(StrMatcher.charSetMatcher((String) null)).isSameAs(StrMatcher.noneMatcher());
+        assertThat(StrMatcher.charSetMatcher("a") instanceof StrMatcher.CharMatcher).isTrue();
     }
 
     //-----------------------------------------------------------------------
     @Test
-    public void testTrimMatcher() {
-        final StrMatcher matcher = StrMatcher.trimMatcher();
-        assertThat(StrMatcher.trimMatcher()).isSameAs(matcher);
+    public void testCommaMatcher() {
+        final StrMatcher matcher = StrMatcher.commaMatcher();
+        assertThat(StrMatcher.commaMatcher()).isSameAs(matcher);
+        assertThat(matcher.isMatch(BUFFER1, 0)).isEqualTo(0);
+        assertThat(matcher.isMatch(BUFFER1, 1)).isEqualTo(1);
         assertThat(matcher.isMatch(BUFFER1, 2)).isEqualTo(0);
-        assertThat(matcher.isMatch(BUFFER1, 3)).isEqualTo(1);
-        assertThat(matcher.isMatch(BUFFER1, 4)).isEqualTo(0);
-        assertThat(matcher.isMatch(BUFFER1, 5)).isEqualTo(1);
-        assertThat(matcher.isMatch(BUFFER1, 6)).isEqualTo(0);
-        assertThat(matcher.isMatch(BUFFER1, 7)).isEqualTo(1);
-        assertThat(matcher.isMatch(BUFFER1, 8)).isEqualTo(1);
-        assertThat(matcher.isMatch(BUFFER1, 9)).isEqualTo(1);
-        assertThat(matcher.isMatch(BUFFER1, 10)).isEqualTo(1);
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testSingleQuoteMatcher() {
-        final StrMatcher matcher = StrMatcher.singleQuoteMatcher();
-        assertThat(StrMatcher.singleQuoteMatcher()).isSameAs(matcher);
-        assertThat(matcher.isMatch(BUFFER1, 10)).isEqualTo(0);
-        assertThat(matcher.isMatch(BUFFER1, 11)).isEqualTo(1);
-        assertThat(matcher.isMatch(BUFFER1, 12)).isEqualTo(0);
     }
 
     //-----------------------------------------------------------------------
@@ -116,12 +96,14 @@ public class StrMatcherTest  {
 
     //-----------------------------------------------------------------------
     @Test
-    public void testQuoteMatcher() {
-        final StrMatcher matcher = StrMatcher.quoteMatcher();
-        assertThat(StrMatcher.quoteMatcher()).isSameAs(matcher);
-        assertThat(matcher.isMatch(BUFFER1, 10)).isEqualTo(0);
-        assertThat(matcher.isMatch(BUFFER1, 11)).isEqualTo(1);
-        assertThat(matcher.isMatch(BUFFER1, 12)).isEqualTo(1);
+    public void testMatcherIndices() {
+        // remember that the API contract is tight for the isMatch() method
+        // all the onus is on the caller, so invalid inputs are not
+        // the concern of StrMatcher, and are not bugs
+        final StrMatcher matcher = StrMatcher.stringMatcher("bc");
+        assertThat(matcher.isMatch(BUFFER2, 1, 1, BUFFER2.length)).isEqualTo(2);
+        assertThat(matcher.isMatch(BUFFER2, 1, 0, 3)).isEqualTo(2);
+        assertThat(matcher.isMatch(BUFFER2, 1, 0, 2)).isEqualTo(0);
     }
 
     //-----------------------------------------------------------------------
@@ -146,44 +128,48 @@ public class StrMatcherTest  {
 
     //-----------------------------------------------------------------------
     @Test
-    public void testCharMatcher_char() {
-        final StrMatcher matcher = StrMatcher.charMatcher('c');
-        assertThat(matcher.isMatch(BUFFER2, 0)).isEqualTo(0);
-        assertThat(matcher.isMatch(BUFFER2, 1)).isEqualTo(0);
-        assertThat(matcher.isMatch(BUFFER2, 2)).isEqualTo(1);
-        assertThat(matcher.isMatch(BUFFER2, 3)).isEqualTo(0);
-        assertThat(matcher.isMatch(BUFFER2, 4)).isEqualTo(0);
-        assertThat(matcher.isMatch(BUFFER2, 5)).isEqualTo(0);
+    public void testQuoteMatcher() {
+        final StrMatcher matcher = StrMatcher.quoteMatcher();
+        assertThat(StrMatcher.quoteMatcher()).isSameAs(matcher);
+        assertThat(matcher.isMatch(BUFFER1, 10)).isEqualTo(0);
+        assertThat(matcher.isMatch(BUFFER1, 11)).isEqualTo(1);
+        assertThat(matcher.isMatch(BUFFER1, 12)).isEqualTo(1);
     }
 
     //-----------------------------------------------------------------------
     @Test
-    public void testCharSetMatcher_String() {
-        final StrMatcher matcher = StrMatcher.charSetMatcher("ace");
-        assertThat(matcher.isMatch(BUFFER2, 0)).isEqualTo(1);
-        assertThat(matcher.isMatch(BUFFER2, 1)).isEqualTo(0);
-        assertThat(matcher.isMatch(BUFFER2, 2)).isEqualTo(1);
-        assertThat(matcher.isMatch(BUFFER2, 3)).isEqualTo(0);
-        assertThat(matcher.isMatch(BUFFER2, 4)).isEqualTo(1);
-        assertThat(matcher.isMatch(BUFFER2, 5)).isEqualTo(0);
-        assertThat(StrMatcher.charSetMatcher("")).isSameAs(StrMatcher.noneMatcher());
-        assertThat(StrMatcher.charSetMatcher((String) null)).isSameAs(StrMatcher.noneMatcher());
-        assertThat(StrMatcher.charSetMatcher("a") instanceof StrMatcher.CharMatcher).isTrue();
+    public void testSingleQuoteMatcher() {
+        final StrMatcher matcher = StrMatcher.singleQuoteMatcher();
+        assertThat(StrMatcher.singleQuoteMatcher()).isSameAs(matcher);
+        assertThat(matcher.isMatch(BUFFER1, 10)).isEqualTo(0);
+        assertThat(matcher.isMatch(BUFFER1, 11)).isEqualTo(1);
+        assertThat(matcher.isMatch(BUFFER1, 12)).isEqualTo(0);
     }
 
     //-----------------------------------------------------------------------
     @Test
-    public void testCharSetMatcher_charArray() {
-        final StrMatcher matcher = StrMatcher.charSetMatcher("ace".toCharArray());
-        assertThat(matcher.isMatch(BUFFER2, 0)).isEqualTo(1);
-        assertThat(matcher.isMatch(BUFFER2, 1)).isEqualTo(0);
-        assertThat(matcher.isMatch(BUFFER2, 2)).isEqualTo(1);
-        assertThat(matcher.isMatch(BUFFER2, 3)).isEqualTo(0);
-        assertThat(matcher.isMatch(BUFFER2, 4)).isEqualTo(1);
-        assertThat(matcher.isMatch(BUFFER2, 5)).isEqualTo(0);
-        assertThat(StrMatcher.charSetMatcher()).isSameAs(StrMatcher.noneMatcher());
-        assertThat(StrMatcher.charSetMatcher((char[]) null)).isSameAs(StrMatcher.noneMatcher());
-        assertThat(StrMatcher.charSetMatcher("a".toCharArray()) instanceof StrMatcher.CharMatcher).isTrue();
+    public void testSpaceMatcher() {
+        final StrMatcher matcher = StrMatcher.spaceMatcher();
+        assertThat(StrMatcher.spaceMatcher()).isSameAs(matcher);
+        assertThat(matcher.isMatch(BUFFER1, 4)).isEqualTo(0);
+        assertThat(matcher.isMatch(BUFFER1, 5)).isEqualTo(1);
+        assertThat(matcher.isMatch(BUFFER1, 6)).isEqualTo(0);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testSplitMatcher() {
+        final StrMatcher matcher = StrMatcher.splitMatcher();
+        assertThat(StrMatcher.splitMatcher()).isSameAs(matcher);
+        assertThat(matcher.isMatch(BUFFER1, 2)).isEqualTo(0);
+        assertThat(matcher.isMatch(BUFFER1, 3)).isEqualTo(1);
+        assertThat(matcher.isMatch(BUFFER1, 4)).isEqualTo(0);
+        assertThat(matcher.isMatch(BUFFER1, 5)).isEqualTo(1);
+        assertThat(matcher.isMatch(BUFFER1, 6)).isEqualTo(0);
+        assertThat(matcher.isMatch(BUFFER1, 7)).isEqualTo(1);
+        assertThat(matcher.isMatch(BUFFER1, 8)).isEqualTo(1);
+        assertThat(matcher.isMatch(BUFFER1, 9)).isEqualTo(1);
+        assertThat(matcher.isMatch(BUFFER1, 10)).isEqualTo(0);
     }
 
     //-----------------------------------------------------------------------
@@ -202,14 +188,28 @@ public class StrMatcherTest  {
 
     //-----------------------------------------------------------------------
     @Test
-    public void testMatcherIndices() {
-        // remember that the API contract is tight for the isMatch() method
-        // all the onus is on the caller, so invalid inputs are not
-        // the concern of StrMatcher, and are not bugs
-        final StrMatcher matcher = StrMatcher.stringMatcher("bc");
-        assertThat(matcher.isMatch(BUFFER2, 1, 1, BUFFER2.length)).isEqualTo(2);
-        assertThat(matcher.isMatch(BUFFER2, 1, 0, 3)).isEqualTo(2);
-        assertThat(matcher.isMatch(BUFFER2, 1, 0, 2)).isEqualTo(0);
+    public void testTabMatcher() {
+        final StrMatcher matcher = StrMatcher.tabMatcher();
+        assertThat(StrMatcher.tabMatcher()).isSameAs(matcher);
+        assertThat(matcher.isMatch(BUFFER1, 2)).isEqualTo(0);
+        assertThat(matcher.isMatch(BUFFER1, 3)).isEqualTo(1);
+        assertThat(matcher.isMatch(BUFFER1, 4)).isEqualTo(0);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testTrimMatcher() {
+        final StrMatcher matcher = StrMatcher.trimMatcher();
+        assertThat(StrMatcher.trimMatcher()).isSameAs(matcher);
+        assertThat(matcher.isMatch(BUFFER1, 2)).isEqualTo(0);
+        assertThat(matcher.isMatch(BUFFER1, 3)).isEqualTo(1);
+        assertThat(matcher.isMatch(BUFFER1, 4)).isEqualTo(0);
+        assertThat(matcher.isMatch(BUFFER1, 5)).isEqualTo(1);
+        assertThat(matcher.isMatch(BUFFER1, 6)).isEqualTo(0);
+        assertThat(matcher.isMatch(BUFFER1, 7)).isEqualTo(1);
+        assertThat(matcher.isMatch(BUFFER1, 8)).isEqualTo(1);
+        assertThat(matcher.isMatch(BUFFER1, 9)).isEqualTo(1);
+        assertThat(matcher.isMatch(BUFFER1, 10)).isEqualTo(1);
     }
 
 }
diff --git a/src/test/java/org/apache/commons/text/StrSubstitutorTest.java b/src/test/java/org/apache/commons/text/StrSubstitutorTest.java
index 6ff8657..efa0ab2 100644
--- a/src/test/java/org/apache/commons/text/StrSubstitutorTest.java
+++ b/src/test/java/org/apache/commons/text/StrSubstitutorTest.java
@@ -44,6 +44,110 @@ public class StrSubstitutorTest {
 
     private Map<String, String> values;
 
+    private void doTestNoReplace(final String replaceTemplate) {
+        final StrSubstitutor sub = new StrSubstitutor(values);
+
+        if (replaceTemplate == null) {
+            assertNull(sub.replace((String) null));
+            assertNull(sub.replace((String) null, 0, 100));
+            assertNull(sub.replace((char[]) null));
+            assertNull(sub.replace((char[]) null, 0, 100));
+            assertNull(sub.replace((StringBuffer) null));
+            assertNull(sub.replace((StringBuffer) null, 0, 100));
+            assertNull(sub.replace((StrBuilder) null));
+            assertNull(sub.replace((StrBuilder) null, 0, 100));
+            assertNull(sub.replace((Object) null));
+            assertFalse(sub.replaceIn((StringBuffer) null));
+            assertFalse(sub.replaceIn((StringBuffer) null, 0, 100));
+            assertFalse(sub.replaceIn((StrBuilder) null));
+            assertFalse(sub.replaceIn((StrBuilder) null, 0, 100));
+        } else {
+            assertEquals(replaceTemplate, sub.replace(replaceTemplate));
+            final StrBuilder bld = new StrBuilder(replaceTemplate);
+            assertFalse(sub.replaceIn(bld));
+            assertEquals(replaceTemplate, bld.toString());
+        }
+    }
+
+    private void doTestReplace(final String expectedResult, final String replaceTemplate, final boolean substring) {
+        final StrSubstitutor sub = new StrSubstitutor(values);
+        doTestReplace(sub, expectedResult, replaceTemplate, substring);
+    }
+
+    //-----------------------------------------------------------------------
+    private void doTestReplace(final StrSubstitutor sub, final String expectedResult, final String replaceTemplate,
+            final boolean substring) {
+        final String expectedShortResult = expectedResult.substring(1, expectedResult.length() - 1);
+
+        // replace using String
+        assertEquals(expectedResult, sub.replace(replaceTemplate));
+        if (substring) {
+            assertEquals(expectedShortResult, sub.replace(replaceTemplate, 1, replaceTemplate.length() - 2));
+        }
+
+        // replace using char[]
+        final char[] chars = replaceTemplate.toCharArray();
+        assertEquals(expectedResult, sub.replace(chars));
+        if (substring) {
+            assertEquals(expectedShortResult, sub.replace(chars, 1, chars.length - 2));
+        }
+
+        // replace using StringBuffer
+        StringBuffer buf = new StringBuffer(replaceTemplate);
+        assertEquals(expectedResult, sub.replace(buf));
+        if (substring) {
+            assertEquals(expectedShortResult, sub.replace(buf, 1, buf.length() - 2));
+        }
+
+        // replace using StringBuilder
+        StringBuilder builder = new StringBuilder(replaceTemplate);
+        assertEquals(expectedResult, sub.replace(builder));
+        if (substring) {
+            assertEquals(expectedShortResult, sub.replace(builder, 1, builder.length() - 2));
+        }
+
+        // replace using StrBuilder
+        StrBuilder bld = new StrBuilder(replaceTemplate);
+        assertEquals(expectedResult, sub.replace(bld));
+        if (substring) {
+            assertEquals(expectedShortResult, sub.replace(bld, 1, bld.length() - 2));
+        }
+
+        // replace using object
+        final MutableObject<String> obj = new MutableObject<>(replaceTemplate);  // toString returns template
+        assertEquals(expectedResult, sub.replace(obj));
+
+        // replace in StringBuffer
+        buf = new StringBuffer(replaceTemplate);
+        assertTrue(sub.replaceIn(buf));
+        assertEquals(expectedResult, buf.toString());
+        if (substring) {
+            buf = new StringBuffer(replaceTemplate);
+            assertTrue(sub.replaceIn(buf, 1, buf.length() - 2));
+            assertEquals(expectedResult, buf.toString());  // expect full result as remainder is untouched
+        }
+
+        // replace in StringBuilder
+        builder = new StringBuilder(replaceTemplate);
+        assertTrue(sub.replaceIn(builder));
+        assertEquals(expectedResult, builder.toString());
+        if (substring) {
+            builder = new StringBuilder(replaceTemplate);
+            assertTrue(sub.replaceIn(builder, 1, builder.length() - 2));
+            assertEquals(expectedResult, builder.toString());  // expect full result as remainder is untouched
+        }
+
+        // replace in StrBuilder
+        bld = new StrBuilder(replaceTemplate);
+        assertTrue(sub.replaceIn(bld));
+        assertEquals(expectedResult, bld.toString());
+        if (substring) {
+            bld = new StrBuilder(replaceTemplate);
+            assertTrue(sub.replaceIn(bld, 1, bld.length() - 2));
+            assertEquals(expectedResult, bld.toString());  // expect full result as remainder is untouched
+        }
+    }
+
     @BeforeEach
     public void setUp() throws Exception {
         values = new HashMap<>();
@@ -56,138 +160,243 @@ public class StrSubstitutorTest {
         values = null;
     }
 
-    //-----------------------------------------------------------------------
     /**
-     * Tests simple key replace.
+     * Tests constructor.
      */
     @Test
-    public void testReplaceSimple() {
-        doTestReplace("The quick brown fox jumps over the lazy dog.", "The ${animal} jumps over the ${target}.", true);
+    public void testConstructorMapFull() {
+        final Map<String, String> map = new HashMap<>();
+        map.put("name", "commons");
+        StrSubstitutor sub = new StrSubstitutor(map, "<", ">", '!');
+        assertEquals("Hi < commons", sub.replace("Hi !< <name>"));
+        sub = new StrSubstitutor(map, "<", ">", '!', "||");
+        assertEquals("Hi < commons", sub.replace("Hi !< <name2||commons>"));
     }
 
     /**
-     * Tests simple key replace.
+     * Tests constructor.
      */
     @Test
-    public void testReplaceSolo() {
-        doTestReplace("quick brown fox", "${animal}", false);
+    public void testConstructorMapPrefixSuffix() {
+        final Map<String, String> map = new HashMap<>();
+        map.put("name", "commons");
+        final StrSubstitutor sub = new StrSubstitutor(map, "<", ">");
+        assertEquals("Hi < commons", sub.replace("Hi $< <name>"));
     }
 
+    //-----------------------------------------------------------------------
     /**
-     * Tests replace with no variables.
+     * Tests constructor.
      */
     @Test
-    public void testReplaceNoVariables() {
-        doTestNoReplace("The balloon arrived.");
+    public void testConstructorNoArgs() {
+        final StrSubstitutor sub = new StrSubstitutor();
+        assertEquals("Hi ${name}", sub.replace("Hi ${name}"));
     }
 
-    /**
-     * Tests replace with null.
-     */
     @Test
-    public void testReplaceNull() {
-        doTestNoReplace(null);
+    public void testCreatesStrSubstitutorTakingStrLookupAndCallsReplaceTakingTwoAndThreeInts() {
+        final Map<String, CharacterPredicates> map = new HashMap<>();
+        final StrLookup.MapStrLookup<CharacterPredicates> strLookupMapStrLookup = new StrLookup.MapStrLookup<>(map);
+        final StrSubstitutor strSubstitutor = new StrSubstitutor(strLookupMapStrLookup);
+
+        assertNull(strSubstitutor.replace((CharSequence) null, 0, 0));
+        assertEquals('$', strSubstitutor.getEscapeChar());
     }
 
     /**
-     * Tests replace with null.
+     * Tests a cyclic replace operation.
+     * The cycle should be detected and cause an exception to be thrown.
      */
     @Test
-    public void testReplaceEmpty() {
-        doTestNoReplace("");
+    public void testCyclicReplacement() {
+        final Map<String, String> map = new HashMap<>();
+        map.put("animal", "${critter}");
+        map.put("target", "${pet}");
+        map.put("pet", "${petCharacteristic} dog");
+        map.put("petCharacteristic", "lazy");
+        map.put("critter", "${critterSpeed} ${critterColor} ${critterType}");
+        map.put("critterSpeed", "quick");
+        map.put("critterColor", "brown");
+        map.put("critterType", "${animal}");
+        final StrSubstitutor sub = new StrSubstitutor(map);
+        assertThrows(IllegalStateException.class, () -> sub.replace("The ${animal} jumps over the ${target}."));
+
+        // also check even when default value is set.
+        map.put("critterType", "${animal:-fox}");
+        assertThrows(IllegalStateException.class,
+                () -> new StrSubstitutor(map).replace("The ${animal} jumps over the ${target}."));
+    }
+
+    @Test
+    public void testDefaultValueDelimiters() {
+        final Map<String, String> map = new HashMap<>();
+        map.put("animal", "fox");
+        map.put("target", "dog");
+
+        StrSubstitutor sub = new StrSubstitutor(map, "${", "}", '$');
+        assertEquals("The fox jumps over the lazy dog. 1234567890.",
+                sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number:-1234567890}."));
+
+        sub = new StrSubstitutor(map, "${", "}", '$', "?:");
+        assertEquals("The fox jumps over the lazy dog. 1234567890.",
+                sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number?:1234567890}."));
+
+        sub = new StrSubstitutor(map, "${", "}", '$', "||");
+        assertEquals("The fox jumps over the lazy dog. 1234567890.",
+                sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number||1234567890}."));
+
+        sub = new StrSubstitutor(map, "${", "}", '$', "!");
+        assertEquals("The fox jumps over the lazy dog. 1234567890.",
+                sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number!1234567890}."));
+
+        sub = new StrSubstitutor(map, "${", "}", '$', "");
+        sub.setValueDelimiterMatcher(null);
+        assertEquals("The fox jumps over the lazy dog. ${undefined.number!1234567890}.",
+                sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number!1234567890}."));
+
+        sub = new StrSubstitutor(map, "${", "}", '$');
+        sub.setValueDelimiterMatcher(null);
+        assertEquals("The fox jumps over the lazy dog. ${undefined.number!1234567890}.",
+                sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number!1234567890}."));
+    }
+
+    @Test
+    public void testDisableSubstitutionInValues() {
+        final StrSubstitutor sub = new StrSubstitutor(values);
+        sub.setDisableSubstitutionInValues(true);
+        values.put("animal", "${critter}");
+        values.put("target", "${pet}");
+        values.put("pet", "${petCharacteristic} dog");
+        values.put("petCharacteristic", "lazy");
+        values.put("critter", "${critterSpeed} ${critterColor} ${critterType}");
+        values.put("critterSpeed", "quick");
+        values.put("critterColor", "brown");
+        values.put("critterType", "fox");
+        doTestReplace(sub, "The ${critter} jumps over the ${pet}.", "The ${animal} jumps over the ${target}.", true);
     }
 
+    //-----------------------------------------------------------------------
     /**
-     * Tests key replace changing map after initialization (not recommended).
+     * Tests get set.
      */
     @Test
-    public void testReplaceChangedMap() {
-        final StrSubstitutor sub = new StrSubstitutor(values);
-        values.put("target", "moon");
-        assertEquals("The quick brown fox jumps over the moon.",
-                sub.replace("The ${animal} jumps over the ${target}."));
+    public void testGetSetEscape() {
+        final StrSubstitutor sub = new StrSubstitutor();
+        assertEquals('$', sub.getEscapeChar());
+        sub.setEscapeChar('<');
+        assertEquals('<', sub.getEscapeChar());
     }
 
     /**
-     * Tests unknown key replace.
+     * Tests get set.
      */
     @Test
-    public void testReplaceUnknownKey() {
-        doTestReplace("The ${person} jumps over the lazy dog.", "The ${person} jumps over the ${target}.", true);
-        doTestReplace("The ${person} jumps over the lazy dog. 1234567890.",
-                "The ${person} jumps over the ${target}. ${undefined.number:-1234567890}.", true);
+    public void testGetSetPrefix() {
+        final StrSubstitutor sub = new StrSubstitutor();
+        assertTrue(sub.getVariablePrefixMatcher() instanceof StrMatcher.StringMatcher);
+        sub.setVariablePrefix('<');
+        assertTrue(sub.getVariablePrefixMatcher() instanceof StrMatcher.CharMatcher);
+
+        sub.setVariablePrefix("<<");
+        assertTrue(sub.getVariablePrefixMatcher() instanceof StrMatcher.StringMatcher);
+        assertThrows(IllegalArgumentException.class, () -> sub.setVariablePrefix((String) null));
+        assertTrue(sub.getVariablePrefixMatcher() instanceof StrMatcher.StringMatcher);
+
+        final StrMatcher matcher = StrMatcher.commaMatcher();
+        sub.setVariablePrefixMatcher(matcher);
+        assertSame(matcher, sub.getVariablePrefixMatcher());
+        assertThrows(IllegalArgumentException.class, () -> sub.setVariablePrefixMatcher((StrMatcher) null));
+        assertSame(matcher, sub.getVariablePrefixMatcher());
     }
 
     /**
-     * Tests adjacent keys.
+     * Tests get set.
      */
     @Test
-    public void testReplaceAdjacentAtStart() {
-        values.put("code", "GBP");
-        values.put("amount", "12.50");
-        final StrSubstitutor sub = new StrSubstitutor(values);
-        assertEquals("GBP12.50 charged", sub.replace("${code}${amount} charged"));
+    public void testGetSetSuffix() {
+        final StrSubstitutor sub = new StrSubstitutor();
+        assertTrue(sub.getVariableSuffixMatcher() instanceof StrMatcher.StringMatcher);
+        sub.setVariableSuffix('<');
+        assertTrue(sub.getVariableSuffixMatcher() instanceof StrMatcher.CharMatcher);
+
+        sub.setVariableSuffix("<<");
+        assertTrue(sub.getVariableSuffixMatcher() instanceof StrMatcher.StringMatcher);
+        assertThrows(IllegalArgumentException.class, () -> sub.setVariableSuffix((String) null));
+        assertTrue(sub.getVariableSuffixMatcher() instanceof StrMatcher.StringMatcher);
+
+        final StrMatcher matcher = StrMatcher.commaMatcher();
+        sub.setVariableSuffixMatcher(matcher);
+        assertSame(matcher, sub.getVariableSuffixMatcher());
+        assertThrows(IllegalArgumentException.class, () -> sub.setVariableSuffixMatcher((StrMatcher) null));
+        assertSame(matcher, sub.getVariableSuffixMatcher());
     }
 
     /**
-     * Tests adjacent keys.
+     * Tests get set.
      */
     @Test
-    public void testReplaceAdjacentAtEnd() {
-        values.put("code", "GBP");
-        values.put("amount", "12.50");
-        final StrSubstitutor sub = new StrSubstitutor(values);
-        assertEquals("Amount is GBP12.50", sub.replace("Amount is ${code}${amount}"));
+    public void testGetSetValueDelimiter() {
+        final StrSubstitutor sub = new StrSubstitutor();
+        assertTrue(sub.getValueDelimiterMatcher() instanceof StrMatcher.StringMatcher);
+        sub.setValueDelimiter(':');
+        assertTrue(sub.getValueDelimiterMatcher() instanceof StrMatcher.CharMatcher);
+
+        sub.setValueDelimiter("||");
+        assertTrue(sub.getValueDelimiterMatcher() instanceof StrMatcher.StringMatcher);
+        sub.setValueDelimiter((String) null);
+        assertNull(sub.getValueDelimiterMatcher());
+
+        final StrMatcher matcher = StrMatcher.commaMatcher();
+        sub.setValueDelimiterMatcher(matcher);
+        assertSame(matcher, sub.getValueDelimiterMatcher());
+        sub.setValueDelimiterMatcher((StrMatcher) null);
+        assertNull(sub.getValueDelimiterMatcher());
     }
 
     /**
-     * Tests simple recursive replace.
+     * Test for LANG-1055: StrSubstitutor.replaceSystemProperties does not work consistently
      */
     @Test
-    public void testReplaceRecursive() {
-        values.put("animal", "${critter}");
-        values.put("target", "${pet}");
-        values.put("pet", "${petCharacteristic} dog");
-        values.put("petCharacteristic", "lazy");
-        values.put("critter", "${critterSpeed} ${critterColor} ${critterType}");
-        values.put("critterSpeed", "quick");
-        values.put("critterColor", "brown");
-        values.put("critterType", "fox");
-        doTestReplace("The quick brown fox jumps over the lazy dog.", "The ${animal} jumps over the ${target}.", true);
+    public void testLANG1055() {
+        System.setProperty("test_key", "test_value");
 
-        values.put("pet", "${petCharacteristicUnknown:-lazy} dog");
-        doTestReplace("The quick brown fox jumps over the lazy dog.", "The ${animal} jumps over the ${target}.", true);
+        final String expected = StrSubstitutor.replace("test_key=${test_key}", System.getProperties());
+        final String actual = StrSubstitutor.replaceSystemProperties("test_key=${test_key}");
+        assertEquals(expected, actual);
     }
 
+    /**
+     * Tests adjacent keys.
+     */
     @Test
-    public void testDisableSubstitutionInValues() {
+    public void testReplaceAdjacentAtEnd() {
+        values.put("code", "GBP");
+        values.put("amount", "12.50");
         final StrSubstitutor sub = new StrSubstitutor(values);
-        sub.setDisableSubstitutionInValues(true);
-        values.put("animal", "${critter}");
-        values.put("target", "${pet}");
-        values.put("pet", "${petCharacteristic} dog");
-        values.put("petCharacteristic", "lazy");
-        values.put("critter", "${critterSpeed} ${critterColor} ${critterType}");
-        values.put("critterSpeed", "quick");
-        values.put("critterColor", "brown");
-        values.put("critterType", "fox");
-        doTestReplace(sub, "The ${critter} jumps over the ${pet}.", "The ${animal} jumps over the ${target}.", true);
+        assertEquals("Amount is GBP12.50", sub.replace("Amount is ${code}${amount}"));
     }
 
     /**
-     * Tests escaping.
+     * Tests adjacent keys.
      */
     @Test
-    public void testReplaceEscaping() {
-        doTestReplace("The ${animal} jumps over the lazy dog.", "The $${animal} jumps over the ${target}.", true);
+    public void testReplaceAdjacentAtStart() {
+        values.put("code", "GBP");
+        values.put("amount", "12.50");
+        final StrSubstitutor sub = new StrSubstitutor(values);
+        assertEquals("GBP12.50 charged", sub.replace("${code}${amount} charged"));
     }
 
     /**
-     * Tests escaping.
+     * Tests key replace changing map after initialization (not recommended).
      */
     @Test
-    public void testReplaceSoloEscaping() {
-        doTestReplace("${animal}", "$${animal}", false);
+    public void testReplaceChangedMap() {
+        final StrSubstitutor sub = new StrSubstitutor(values);
+        values.put("target", "moon");
+        assertEquals("The quick brown fox jumps over the moon.",
+                sub.replace("The ${animal} jumps over the ${target}."));
     }
 
     /**
@@ -202,112 +411,77 @@ public class StrSubstitutorTest {
     }
 
     /**
-     * Tests when no prefix or suffix.
+     * Tests replace with null.
      */
     @Test
-    public void testReplaceNoPrefixNoSuffix() {
-        doTestReplace("The animal jumps over the lazy dog.", "The animal jumps over the ${target}.", true);
+    public void testReplaceEmpty() {
+        doTestNoReplace("");
     }
 
     /**
-     * Tests when no incomplete prefix.
+     * Tests when no variable name.
      */
     @Test
-    public void testReplaceIncompletePrefix() {
-        doTestReplace("The {animal} jumps over the lazy dog.", "The {animal} jumps over the ${target}.", true);
+    public void testReplaceEmptyKeys() {
+        doTestReplace("The ${} jumps over the lazy dog.", "The ${} jumps over the ${target}.", true);
+        doTestReplace("The animal jumps over the lazy dog.", "The ${:-animal} jumps over the ${target}.", true);
     }
 
     /**
-     * Tests when prefix but no suffix.
+     * Tests escaping.
      */
     @Test
-    public void testReplacePrefixNoSuffix() {
-        doTestReplace("The ${animal jumps over the ${target} lazy dog.",
-                "The ${animal jumps over the ${target} ${target}.", true);
+    public void testReplaceEscaping() {
+        doTestReplace("The ${animal} jumps over the lazy dog.", "The $${animal} jumps over the ${target}.", true);
     }
 
     /**
-     * Tests when suffix but no prefix.
+     * Tests when no incomplete prefix.
      */
     @Test
-    public void testReplaceNoPrefixSuffix() {
-        doTestReplace("The animal} jumps over the lazy dog.", "The animal} jumps over the ${target}.", true);
+    public void testReplaceIncompletePrefix() {
+        doTestReplace("The {animal} jumps over the lazy dog.", "The {animal} jumps over the ${target}.", true);
     }
 
-    /**
-     * Tests when no variable name.
-     */
     @Test
-    public void testReplaceEmptyKeys() {
-        doTestReplace("The ${} jumps over the lazy dog.", "The ${} jumps over the ${target}.", true);
-        doTestReplace("The animal jumps over the lazy dog.", "The ${:-animal} jumps over the ${target}.", true);
+    public void testReplaceInTakingStringBufferWithNonNull() {
+        final StrSubstitutor strSubstitutor =
+                new StrSubstitutor(new HashMap<String, String>(), "WV@i#y?N*[", "WV@i#y?N*[", '*');
+
+        assertFalse(strSubstitutor.isPreserveEscapes());
+        assertFalse(strSubstitutor.replaceIn(new StringBuffer("WV@i#y?N*[")));
+        assertEquals('*', strSubstitutor.getEscapeChar());
     }
 
-    /**
-     * Tests replace creates output same as input.
-     */
     @Test
-    public void testReplaceToIdentical() {
-        values.put("animal", "$${${thing}}");
-        values.put("thing", "animal");
-        doTestReplace("The ${animal} jumps.", "The ${animal} jumps.", true);
+    public void testReplaceInTakingStringBuilderWithNonNull() {
+        final StrLookup<String> strLookup = StrLookup.systemPropertiesLookup();
+        final StrSubstitutor strSubstitutor = new StrSubstitutor(strLookup, "b<H", "b<H", '\'');
+        final StringBuilder stringBuilder = new StringBuilder((CharSequence) "b<H");
+
+        assertEquals('\'', strSubstitutor.getEscapeChar());
+        assertFalse(strSubstitutor.replaceIn(stringBuilder));
     }
 
-    /**
-     * Tests a cyclic replace operation.
-     * The cycle should be detected and cause an exception to be thrown.
-     */
     @Test
-    public void testCyclicReplacement() {
-        final Map<String, String> map = new HashMap<>();
-        map.put("animal", "${critter}");
-        map.put("target", "${pet}");
-        map.put("pet", "${petCharacteristic} dog");
-        map.put("petCharacteristic", "lazy");
-        map.put("critter", "${critterSpeed} ${critterColor} ${critterType}");
-        map.put("critterSpeed", "quick");
-        map.put("critterColor", "brown");
-        map.put("critterType", "${animal}");
-        final StrSubstitutor sub = new StrSubstitutor(map);
-        assertThrows(IllegalStateException.class, () -> sub.replace("The ${animal} jumps over the ${target}."));
+    public void testReplaceInTakingStringBuilderWithNull() {
+        final Map<String, Object> map = new HashMap<>();
+        final StrSubstitutor strSubstitutor = new StrSubstitutor(map, "", "", 'T', "K+<'f");
 
-        // also check even when default value is set.
-        map.put("critterType", "${animal:-fox}");
-        assertThrows(IllegalStateException.class,
-                () -> new StrSubstitutor(map).replace("The ${animal} jumps over the ${target}."));
+        assertFalse(strSubstitutor.replaceIn((StringBuilder) null));
     }
 
-    /**
-     * Tests interpolation with weird boundary patterns.
-     */
     @Test
-    public void testReplaceWeirdPattens() {
-        doTestNoReplace("");
-        doTestNoReplace("${}");
-        doTestNoReplace("${ }");
-        doTestNoReplace("${\t}");
-        doTestNoReplace("${\n}");
-        doTestNoReplace("${\b}");
-        doTestNoReplace("${");
-        doTestNoReplace("$}");
-        doTestNoReplace("}");
-        doTestNoReplace("${}$");
-        doTestNoReplace("${${");
-        doTestNoReplace("${${}}");
-        doTestNoReplace("${$${}}");
-        doTestNoReplace("${$$${}}");
-        doTestNoReplace("${$$${$}}");
-        doTestNoReplace("${${}}");
-        doTestNoReplace("${${ }}");
-    }
+    public void testReplaceInTakingTwoAndThreeIntsReturningFalse() {
+        final Map<String, Object> hashMap = new HashMap<>();
+        final StrLookup.MapStrLookup<Object> strLookupMapStrLookup = new StrLookup.MapStrLookup<>(hashMap);
+        final StrMatcher strMatcher = StrMatcher.tabMatcher();
+        final StrSubstitutor strSubstitutor =
+                new StrSubstitutor(strLookupMapStrLookup, strMatcher, strMatcher, 'b', strMatcher);
 
-    /**
-     * Tests simple key replace.
-     */
-    @Test
-    public void testReplacePartialString_noReplace() {
-        final StrSubstitutor sub = new StrSubstitutor();
-        assertEquals("${animal} jumps", sub.replace("The ${animal} jumps over the ${target}.", 4, 15));
+        assertFalse(strSubstitutor.replaceIn((StringBuilder) null, 1315, (-1369)));
+        assertEquals('b', strSubstitutor.getEscapeChar());
+        assertFalse(strSubstitutor.isPreserveEscapes());
     }
 
     /**
@@ -370,173 +544,190 @@ public class StrSubstitutorTest {
                 sub.replace("The ${animal.${species.${unknownColor:-brown}}} jumps over the ${target}."));
     }
 
+    /**
+     * Tests when no prefix or suffix.
+     */
     @Test
-    public void testDefaultValueDelimiters() {
-        final Map<String, String> map = new HashMap<>();
-        map.put("animal", "fox");
-        map.put("target", "dog");
-
-        StrSubstitutor sub = new StrSubstitutor(map, "${", "}", '$');
-        assertEquals("The fox jumps over the lazy dog. 1234567890.",
-                sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number:-1234567890}."));
+    public void testReplaceNoPrefixNoSuffix() {
+        doTestReplace("The animal jumps over the lazy dog.", "The animal jumps over the ${target}.", true);
+    }
 
-        sub = new StrSubstitutor(map, "${", "}", '$', "?:");
-        assertEquals("The fox jumps over the lazy dog. 1234567890.",
-                sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number?:1234567890}."));
+    /**
+     * Tests when suffix but no prefix.
+     */
+    @Test
+    public void testReplaceNoPrefixSuffix() {
+        doTestReplace("The animal} jumps over the lazy dog.", "The animal} jumps over the ${target}.", true);
+    }
 
-        sub = new StrSubstitutor(map, "${", "}", '$', "||");
-        assertEquals("The fox jumps over the lazy dog. 1234567890.",
-                sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number||1234567890}."));
+    /**
+     * Tests replace with no variables.
+     */
+    @Test
+    public void testReplaceNoVariables() {
+        doTestNoReplace("The balloon arrived.");
+    }
 
-        sub = new StrSubstitutor(map, "${", "}", '$', "!");
-        assertEquals("The fox jumps over the lazy dog. 1234567890.",
-                sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number!1234567890}."));
+    /**
+     * Tests replace with null.
+     */
+    @Test
+    public void testReplaceNull() {
+        doTestNoReplace(null);
+    }
 
-        sub = new StrSubstitutor(map, "${", "}", '$', "");
-        sub.setValueDelimiterMatcher(null);
-        assertEquals("The fox jumps over the lazy dog. ${undefined.number!1234567890}.",
-                sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number!1234567890}."));
+    /**
+     * Tests simple key replace.
+     */
+    @Test
+    public void testReplacePartialString_noReplace() {
+        final StrSubstitutor sub = new StrSubstitutor();
+        assertEquals("${animal} jumps", sub.replace("The ${animal} jumps over the ${target}.", 4, 15));
+    }
 
-        sub = new StrSubstitutor(map, "${", "}", '$');
-        sub.setValueDelimiterMatcher(null);
-        assertEquals("The fox jumps over the lazy dog. ${undefined.number!1234567890}.",
-                sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number!1234567890}."));
+    /**
+     * Tests when prefix but no suffix.
+     */
+    @Test
+    public void testReplacePrefixNoSuffix() {
+        doTestReplace("The ${animal jumps over the ${target} lazy dog.",
+                "The ${animal jumps over the ${target} ${target}.", true);
     }
 
-    //-----------------------------------------------------------------------
     /**
-     * Tests protected.
+     * Tests simple recursive replace.
      */
     @Test
-    public void testResolveVariable() {
-        final StrBuilder builder = new StrBuilder("Hi ${name}!");
-        final Map<String, String> map = new HashMap<>();
-        map.put("name", "commons");
-        final StrSubstitutor sub = new StrSubstitutor(map) {
-            @Override
-            protected String resolveVariable(final String variableName, final StrBuilder buf, final int startPos,
-                    final int endPos) {
-                assertEquals("name", variableName);
-                assertSame(builder, buf);
-                assertEquals(3, startPos);
-                assertEquals(10, endPos);
-                return "jakarta";
-            }
-        };
-        sub.replaceIn(builder);
-        assertEquals("Hi jakarta!", builder.toString());
+    public void testReplaceRecursive() {
+        values.put("animal", "${critter}");
+        values.put("target", "${pet}");
+        values.put("pet", "${petCharacteristic} dog");
+        values.put("petCharacteristic", "lazy");
+        values.put("critter", "${critterSpeed} ${critterColor} ${critterType}");
+        values.put("critterSpeed", "quick");
+        values.put("critterColor", "brown");
+        values.put("critterType", "fox");
+        doTestReplace("The quick brown fox jumps over the lazy dog.", "The ${animal} jumps over the ${target}.", true);
+
+        values.put("pet", "${petCharacteristicUnknown:-lazy} dog");
+        doTestReplace("The quick brown fox jumps over the lazy dog.", "The ${animal} jumps over the ${target}.", true);
     }
 
     //-----------------------------------------------------------------------
     /**
-     * Tests constructor.
+     * Tests simple key replace.
      */
     @Test
-    public void testConstructorNoArgs() {
-        final StrSubstitutor sub = new StrSubstitutor();
-        assertEquals("Hi ${name}", sub.replace("Hi ${name}"));
+    public void testReplaceSimple() {
+        doTestReplace("The quick brown fox jumps over the lazy dog.", "The ${animal} jumps over the ${target}.", true);
     }
 
     /**
-     * Tests constructor.
+     * Tests simple key replace.
      */
     @Test
-    public void testConstructorMapPrefixSuffix() {
-        final Map<String, String> map = new HashMap<>();
-        map.put("name", "commons");
-        final StrSubstitutor sub = new StrSubstitutor(map, "<", ">");
-        assertEquals("Hi < commons", sub.replace("Hi $< <name>"));
+    public void testReplaceSolo() {
+        doTestReplace("quick brown fox", "${animal}", false);
     }
 
     /**
-     * Tests constructor.
+     * Tests escaping.
      */
     @Test
-    public void testConstructorMapFull() {
-        final Map<String, String> map = new HashMap<>();
-        map.put("name", "commons");
-        StrSubstitutor sub = new StrSubstitutor(map, "<", ">", '!');
-        assertEquals("Hi < commons", sub.replace("Hi !< <name>"));
-        sub = new StrSubstitutor(map, "<", ">", '!', "||");
-        assertEquals("Hi < commons", sub.replace("Hi !< <name2||commons>"));
+    public void testReplaceSoloEscaping() {
+        doTestReplace("${animal}", "$${animal}", false);
+    }
+
+    @Test
+    public void testReplaceTakingCharSequenceReturningNull() {
+        final StrSubstitutor strSubstitutor = new StrSubstitutor((StrLookup<?>) null);
+
+        assertNull(strSubstitutor.replace((CharSequence) null));
+        assertFalse(strSubstitutor.isPreserveEscapes());
+        assertEquals('$', strSubstitutor.getEscapeChar());
+    }
+
+    @Test
+    public void testReplaceTakingThreeArgumentsThrowsNullPointerException() {
+        assertThatNullPointerException().isThrownBy(() -> StrSubstitutor.replace(null, (Properties) null));
     }
 
-    //-----------------------------------------------------------------------
     /**
-     * Tests get set.
+     * Tests replace creates output same as input.
      */
     @Test
-    public void testGetSetEscape() {
-        final StrSubstitutor sub = new StrSubstitutor();
-        assertEquals('$', sub.getEscapeChar());
-        sub.setEscapeChar('<');
-        assertEquals('<', sub.getEscapeChar());
+    public void testReplaceToIdentical() {
+        values.put("animal", "$${${thing}}");
+        values.put("thing", "animal");
+        doTestReplace("The ${animal} jumps.", "The ${animal} jumps.", true);
     }
 
     /**
-     * Tests get set.
+     * Tests unknown key replace.
      */
     @Test
-    public void testGetSetPrefix() {
-        final StrSubstitutor sub = new StrSubstitutor();
-        assertTrue(sub.getVariablePrefixMatcher() instanceof StrMatcher.StringMatcher);
-        sub.setVariablePrefix('<');
-        assertTrue(sub.getVariablePrefixMatcher() instanceof StrMatcher.CharMatcher);
-
-        sub.setVariablePrefix("<<");
-        assertTrue(sub.getVariablePrefixMatcher() instanceof StrMatcher.StringMatcher);
-        assertThrows(IllegalArgumentException.class, () -> sub.setVariablePrefix((String) null));
-        assertTrue(sub.getVariablePrefixMatcher() instanceof StrMatcher.StringMatcher);
+    public void testReplaceUnknownKey() {
+        doTestReplace("The ${person} jumps over the lazy dog.", "The ${person} jumps over the ${target}.", true);
+        doTestReplace("The ${person} jumps over the lazy dog. 1234567890.",
+                "The ${person} jumps over the ${target}. ${undefined.number:-1234567890}.", true);
+    }
 
-        final StrMatcher matcher = StrMatcher.commaMatcher();
-        sub.setVariablePrefixMatcher(matcher);
-        assertSame(matcher, sub.getVariablePrefixMatcher());
-        assertThrows(IllegalArgumentException.class, () -> sub.setVariablePrefixMatcher((StrMatcher) null));
-        assertSame(matcher, sub.getVariablePrefixMatcher());
+    /**
+     * Tests interpolation with weird boundary patterns.
+     */
+    @Test
+    public void testReplaceWeirdPattens() {
+        doTestNoReplace("");
+        doTestNoReplace("${}");
+        doTestNoReplace("${ }");
+        doTestNoReplace("${\t}");
+        doTestNoReplace("${\n}");
+        doTestNoReplace("${\b}");
+        doTestNoReplace("${");
+        doTestNoReplace("$}");
+        doTestNoReplace("}");
+        doTestNoReplace("${}$");
+        doTestNoReplace("${${");
+        doTestNoReplace("${${}}");
+        doTestNoReplace("${$${}}");
+        doTestNoReplace("${$$${}}");
+        doTestNoReplace("${$$${$}}");
+        doTestNoReplace("${${}}");
+        doTestNoReplace("${${ }}");
     }
 
+    //-----------------------------------------------------------------------
     /**
-     * Tests get set.
+     * Tests protected.
      */
     @Test
-    public void testGetSetSuffix() {
-        final StrSubstitutor sub = new StrSubstitutor();
-        assertTrue(sub.getVariableSuffixMatcher() instanceof StrMatcher.StringMatcher);
-        sub.setVariableSuffix('<');
-        assertTrue(sub.getVariableSuffixMatcher() instanceof StrMatcher.CharMatcher);
-
-        sub.setVariableSuffix("<<");
-        assertTrue(sub.getVariableSuffixMatcher() instanceof StrMatcher.StringMatcher);
-        assertThrows(IllegalArgumentException.class, () -> sub.setVariableSuffix((String) null));
-        assertTrue(sub.getVariableSuffixMatcher() instanceof StrMatcher.StringMatcher);
-
-        final StrMatcher matcher = StrMatcher.commaMatcher();
-        sub.setVariableSuffixMatcher(matcher);
-        assertSame(matcher, sub.getVariableSuffixMatcher());
-        assertThrows(IllegalArgumentException.class, () -> sub.setVariableSuffixMatcher((StrMatcher) null));
-        assertSame(matcher, sub.getVariableSuffixMatcher());
+    public void testResolveVariable() {
+        final StrBuilder builder = new StrBuilder("Hi ${name}!");
+        final Map<String, String> map = new HashMap<>();
+        map.put("name", "commons");
+        final StrSubstitutor sub = new StrSubstitutor(map) {
+            @Override
+            protected String resolveVariable(final String variableName, final StrBuilder buf, final int startPos,
+                    final int endPos) {
+                assertEquals("name", variableName);
+                assertSame(builder, buf);
+                assertEquals(3, startPos);
+                assertEquals(10, endPos);
+                return "jakarta";
+            }
+        };
+        sub.replaceIn(builder);
+        assertEquals("Hi jakarta!", builder.toString());
     }
 
-    /**
-     * Tests get set.
-     */
     @Test
-    public void testGetSetValueDelimiter() {
-        final StrSubstitutor sub = new StrSubstitutor();
-        assertTrue(sub.getValueDelimiterMatcher() instanceof StrMatcher.StringMatcher);
-        sub.setValueDelimiter(':');
-        assertTrue(sub.getValueDelimiterMatcher() instanceof StrMatcher.CharMatcher);
-
-        sub.setValueDelimiter("||");
-        assertTrue(sub.getValueDelimiterMatcher() instanceof StrMatcher.StringMatcher);
-        sub.setValueDelimiter((String) null);
-        assertNull(sub.getValueDelimiterMatcher());
-
-        final StrMatcher matcher = StrMatcher.commaMatcher();
-        sub.setValueDelimiterMatcher(matcher);
-        assertSame(matcher, sub.getValueDelimiterMatcher());
-        sub.setValueDelimiterMatcher((StrMatcher) null);
-        assertNull(sub.getValueDelimiterMatcher());
+    public void testSamePrefixAndSuffix() {
+        final Map<String, String> map = new HashMap<>();
+        map.put("greeting", "Hello");
+        map.put(" there ", "XXX");
+        map.put("name", "commons");
+        assertEquals("Hi commons!", StrSubstitutor.replace("Hi @name@!", map, "@", "@"));
+        assertEquals("Hello there commons!", StrSubstitutor.replace("@greeting@ there @name@!", map, "@", "@"));
     }
 
     //-----------------------------------------------------------------------
@@ -577,18 +768,6 @@ public class StrSubstitutorTest {
     }
 
     /**
-     * Test for LANG-1055: StrSubstitutor.replaceSystemProperties does not work consistently
-     */
-    @Test
-    public void testLANG1055() {
-        System.setProperty("test_key", "test_value");
-
-        final String expected = StrSubstitutor.replace("test_key=${test_key}", System.getProperties());
-        final String actual = StrSubstitutor.replaceSystemProperties("test_key=${test_key}");
-        assertEquals(expected, actual);
-    }
-
-    /**
      * Test the replace of a properties object
      */
     @Test
@@ -603,16 +782,6 @@ public class StrSubstitutorTest {
     }
 
     @Test
-    public void testSamePrefixAndSuffix() {
-        final Map<String, String> map = new HashMap<>();
-        map.put("greeting", "Hello");
-        map.put(" there ", "XXX");
-        map.put("name", "commons");
-        assertEquals("Hi commons!", StrSubstitutor.replace("Hi @name@!", map, "@", "@"));
-        assertEquals("Hello there commons!", StrSubstitutor.replace("@greeting@ there @name@!", map, "@", "@"));
-    }
-
-    @Test
     public void testSubstitutePreserveEscape() {
         final String org = "${not-escaped} $${escaped}";
         final Map<String, String> map = new HashMap<>();
@@ -627,173 +796,4 @@ public class StrSubstitutorTest {
         assertEquals("value $${escaped}", sub.replace(org));
     }
 
-    private void doTestReplace(final String expectedResult, final String replaceTemplate, final boolean substring) {
-        final StrSubstitutor sub = new StrSubstitutor(values);
-        doTestReplace(sub, expectedResult, replaceTemplate, substring);
-    }
-
-    //-----------------------------------------------------------------------
-    private void doTestReplace(final StrSubstitutor sub, final String expectedResult, final String replaceTemplate,
-            final boolean substring) {
-        final String expectedShortResult = expectedResult.substring(1, expectedResult.length() - 1);
-
-        // replace using String
-        assertEquals(expectedResult, sub.replace(replaceTemplate));
-        if (substring) {
-            assertEquals(expectedShortResult, sub.replace(replaceTemplate, 1, replaceTemplate.length() - 2));
-        }
-
-        // replace using char[]
-        final char[] chars = replaceTemplate.toCharArray();
-        assertEquals(expectedResult, sub.replace(chars));
-        if (substring) {
-            assertEquals(expectedShortResult, sub.replace(chars, 1, chars.length - 2));
-        }
-
-        // replace using StringBuffer
-        StringBuffer buf = new StringBuffer(replaceTemplate);
-        assertEquals(expectedResult, sub.replace(buf));
-        if (substring) {
-            assertEquals(expectedShortResult, sub.replace(buf, 1, buf.length() - 2));
-        }
-
-        // replace using StringBuilder
-        StringBuilder builder = new StringBuilder(replaceTemplate);
-        assertEquals(expectedResult, sub.replace(builder));
-        if (substring) {
-            assertEquals(expectedShortResult, sub.replace(builder, 1, builder.length() - 2));
-        }
-
-        // replace using StrBuilder
-        StrBuilder bld = new StrBuilder(replaceTemplate);
-        assertEquals(expectedResult, sub.replace(bld));
-        if (substring) {
-            assertEquals(expectedShortResult, sub.replace(bld, 1, bld.length() - 2));
-        }
-
-        // replace using object
-        final MutableObject<String> obj = new MutableObject<>(replaceTemplate);  // toString returns template
-        assertEquals(expectedResult, sub.replace(obj));
-
-        // replace in StringBuffer
-        buf = new StringBuffer(replaceTemplate);
-        assertTrue(sub.replaceIn(buf));
-        assertEquals(expectedResult, buf.toString());
-        if (substring) {
-            buf = new StringBuffer(replaceTemplate);
-            assertTrue(sub.replaceIn(buf, 1, buf.length() - 2));
-            assertEquals(expectedResult, buf.toString());  // expect full result as remainder is untouched
-        }
-
-        // replace in StringBuilder
-        builder = new StringBuilder(replaceTemplate);
-        assertTrue(sub.replaceIn(builder));
-        assertEquals(expectedResult, builder.toString());
-        if (substring) {
-            builder = new StringBuilder(replaceTemplate);
-            assertTrue(sub.replaceIn(builder, 1, builder.length() - 2));
-            assertEquals(expectedResult, builder.toString());  // expect full result as remainder is untouched
-        }
-
-        // replace in StrBuilder
-        bld = new StrBuilder(replaceTemplate);
-        assertTrue(sub.replaceIn(bld));
-        assertEquals(expectedResult, bld.toString());
-        if (substring) {
-            bld = new StrBuilder(replaceTemplate);
-            assertTrue(sub.replaceIn(bld, 1, bld.length() - 2));
-            assertEquals(expectedResult, bld.toString());  // expect full result as remainder is untouched
-        }
-    }
-
-    private void doTestNoReplace(final String replaceTemplate) {
-        final StrSubstitutor sub = new StrSubstitutor(values);
-
-        if (replaceTemplate == null) {
-            assertNull(sub.replace((String) null));
-            assertNull(sub.replace((String) null, 0, 100));
-            assertNull(sub.replace((char[]) null));
-            assertNull(sub.replace((char[]) null, 0, 100));
-            assertNull(sub.replace((StringBuffer) null));
-            assertNull(sub.replace((StringBuffer) null, 0, 100));
-            assertNull(sub.replace((StrBuilder) null));
-            assertNull(sub.replace((StrBuilder) null, 0, 100));
-            assertNull(sub.replace((Object) null));
-            assertFalse(sub.replaceIn((StringBuffer) null));
-            assertFalse(sub.replaceIn((StringBuffer) null, 0, 100));
-            assertFalse(sub.replaceIn((StrBuilder) null));
-            assertFalse(sub.replaceIn((StrBuilder) null, 0, 100));
-        } else {
-            assertEquals(replaceTemplate, sub.replace(replaceTemplate));
-            final StrBuilder bld = new StrBuilder(replaceTemplate);
-            assertFalse(sub.replaceIn(bld));
-            assertEquals(replaceTemplate, bld.toString());
-        }
-    }
-
-    @Test
-    public void testReplaceInTakingTwoAndThreeIntsReturningFalse() {
-        final Map<String, Object> hashMap = new HashMap<>();
-        final StrLookup.MapStrLookup<Object> strLookupMapStrLookup = new StrLookup.MapStrLookup<>(hashMap);
-        final StrMatcher strMatcher = StrMatcher.tabMatcher();
-        final StrSubstitutor strSubstitutor =
-                new StrSubstitutor(strLookupMapStrLookup, strMatcher, strMatcher, 'b', strMatcher);
-
-        assertFalse(strSubstitutor.replaceIn((StringBuilder) null, 1315, (-1369)));
-        assertEquals('b', strSubstitutor.getEscapeChar());
-        assertFalse(strSubstitutor.isPreserveEscapes());
-    }
-
-    @Test
-    public void testReplaceInTakingStringBuilderWithNonNull() {
-        final StrLookup<String> strLookup = StrLookup.systemPropertiesLookup();
-        final StrSubstitutor strSubstitutor = new StrSubstitutor(strLookup, "b<H", "b<H", '\'');
-        final StringBuilder stringBuilder = new StringBuilder((CharSequence) "b<H");
-
-        assertEquals('\'', strSubstitutor.getEscapeChar());
-        assertFalse(strSubstitutor.replaceIn(stringBuilder));
-    }
-
-    @Test
-    public void testReplaceInTakingStringBufferWithNonNull() {
-        final StrSubstitutor strSubstitutor =
-                new StrSubstitutor(new HashMap<String, String>(), "WV@i#y?N*[", "WV@i#y?N*[", '*');
-
-        assertFalse(strSubstitutor.isPreserveEscapes());
-        assertFalse(strSubstitutor.replaceIn(new StringBuffer("WV@i#y?N*[")));
-        assertEquals('*', strSubstitutor.getEscapeChar());
-    }
-
-    @Test
-    public void testCreatesStrSubstitutorTakingStrLookupAndCallsReplaceTakingTwoAndThreeInts() {
-        final Map<String, CharacterPredicates> map = new HashMap<>();
-        final StrLookup.MapStrLookup<CharacterPredicates> strLookupMapStrLookup = new StrLookup.MapStrLookup<>(map);
-        final StrSubstitutor strSubstitutor = new StrSubstitutor(strLookupMapStrLookup);
-
-        assertNull(strSubstitutor.replace((CharSequence) null, 0, 0));
-        assertEquals('$', strSubstitutor.getEscapeChar());
-    }
-
-    @Test
-    public void testReplaceTakingCharSequenceReturningNull() {
-        final StrSubstitutor strSubstitutor = new StrSubstitutor((StrLookup<?>) null);
-
-        assertNull(strSubstitutor.replace((CharSequence) null));
-        assertFalse(strSubstitutor.isPreserveEscapes());
-        assertEquals('$', strSubstitutor.getEscapeChar());
-    }
-
-    @Test
-    public void testReplaceTakingThreeArgumentsThrowsNullPointerException() {
-        assertThatNullPointerException().isThrownBy(() -> StrSubstitutor.replace(null, (Properties) null));
-    }
-
-    @Test
-    public void testReplaceInTakingStringBuilderWithNull() {
-        final Map<String, Object> map = new HashMap<>();
-        final StrSubstitutor strSubstitutor = new StrSubstitutor(map, "", "", 'T', "K+<'f");
-
-        assertFalse(strSubstitutor.replaceIn((StringBuilder) null));
-    }
-
 }
diff --git a/src/test/java/org/apache/commons/text/StrTokenizerTest.java b/src/test/java/org/apache/commons/text/StrTokenizerTest.java
index 744e598..0e94078 100644
--- a/src/test/java/org/apache/commons/text/StrTokenizerTest.java
+++ b/src/test/java/org/apache/commons/text/StrTokenizerTest.java
@@ -299,63 +299,82 @@ public class StrTokenizerTest {
     }
 
     @Test
-    public void testDelimString() {
-        final String input = "a##b##c";
-        final StrTokenizer tok = new StrTokenizer(input, "##");
-
+    public void testBasicEmpty1() {
+        final String input = "a  b c";
+        final StrTokenizer tok = new StrTokenizer(input);
+        tok.setIgnoreEmptyTokens(false);
         assertEquals("a", tok.next());
+        assertEquals("", tok.next());
         assertEquals("b", tok.next());
         assertEquals("c", tok.next());
         assertFalse(tok.hasNext());
     }
 
     @Test
-    public void testDelimMatcher() {
-        final String input = "a/b\\c";
-        final StrMatcher delimMatcher = new StrMatcher.CharSetMatcher(new char[] {'/', '\\'});
-
-        final StrTokenizer tok = new StrTokenizer(input, delimMatcher);
+    public void testBasicEmpty2() {
+        final String input = "a  b c";
+        final StrTokenizer tok = new StrTokenizer(input);
+        tok.setIgnoreEmptyTokens(false);
+        tok.setEmptyTokenAsNull(true);
         assertEquals("a", tok.next());
+        assertNull(tok.next());
         assertEquals("b", tok.next());
         assertEquals("c", tok.next());
         assertFalse(tok.hasNext());
     }
 
     @Test
-    public void testDelimMatcherQuoteMatcher() {
-        final String input = "`a`;`b`;`c`";
-        final StrMatcher delimMatcher = new StrMatcher.CharSetMatcher(new char[] {';'});
-        final StrMatcher quoteMatcher = new StrMatcher.CharSetMatcher(new char[] {'`'});
+    public void testBasicIgnoreTrimmed1() {
+        final String input = "a: bIGNOREc : ";
+        final StrTokenizer tok = new StrTokenizer(input, ':');
+        tok.setIgnoredMatcher(StrMatcher.stringMatcher("IGNORE"));
+        tok.setTrimmerMatcher(StrMatcher.trimMatcher());
+        tok.setIgnoreEmptyTokens(false);
+        tok.setEmptyTokenAsNull(true);
+        assertEquals("a", tok.next());
+        assertEquals("bc", tok.next());
+        assertNull(tok.next());
+        assertFalse(tok.hasNext());
+    }
 
-        final StrTokenizer tok = new StrTokenizer(input, delimMatcher, quoteMatcher);
+    @Test
+    public void testBasicIgnoreTrimmed2() {
+        final String input = "IGNOREaIGNORE: IGNORE bIGNOREc IGNORE : IGNORE ";
+        final StrTokenizer tok = new StrTokenizer(input, ':');
+        tok.setIgnoredMatcher(StrMatcher.stringMatcher("IGNORE"));
+        tok.setTrimmerMatcher(StrMatcher.trimMatcher());
+        tok.setIgnoreEmptyTokens(false);
+        tok.setEmptyTokenAsNull(true);
         assertEquals("a", tok.next());
-        assertEquals("b", tok.next());
-        assertEquals("c", tok.next());
+        assertEquals("bc", tok.next());
+        assertNull(tok.next());
         assertFalse(tok.hasNext());
     }
 
     @Test
-    public void testBasicEmpty1() {
-        final String input = "a  b c";
-        final StrTokenizer tok = new StrTokenizer(input);
+    public void testBasicIgnoreTrimmed3() {
+        final String input = "IGNOREaIGNORE: IGNORE bIGNOREc IGNORE : IGNORE ";
+        final StrTokenizer tok = new StrTokenizer(input, ':');
+        tok.setIgnoredMatcher(StrMatcher.stringMatcher("IGNORE"));
         tok.setIgnoreEmptyTokens(false);
+        tok.setEmptyTokenAsNull(true);
         assertEquals("a", tok.next());
-        assertEquals("", tok.next());
-        assertEquals("b", tok.next());
-        assertEquals("c", tok.next());
+        assertEquals("  bc  ", tok.next());
+        assertEquals("  ", tok.next());
         assertFalse(tok.hasNext());
     }
 
     @Test
-    public void testBasicEmpty2() {
-        final String input = "a  b c";
-        final StrTokenizer tok = new StrTokenizer(input);
+    public void testBasicIgnoreTrimmed4() {
+        final String input = "IGNOREaIGNORE: IGNORE 'bIGNOREc'IGNORE'd' IGNORE : IGNORE ";
+        final StrTokenizer tok = new StrTokenizer(input, ':', '\'');
+        tok.setIgnoredMatcher(StrMatcher.stringMatcher("IGNORE"));
+        tok.setTrimmerMatcher(StrMatcher.trimMatcher());
         tok.setIgnoreEmptyTokens(false);
         tok.setEmptyTokenAsNull(true);
         assertEquals("a", tok.next());
+        assertEquals("bIGNOREcd", tok.next());
         assertNull(tok.next());
-        assertEquals("b", tok.next());
-        assertEquals("c", tok.next());
         assertFalse(tok.hasNext());
     }
 
@@ -478,119 +497,6 @@ public class StrTokenizerTest {
         assertFalse(tok.hasNext());
     }
 
-    @Test
-    public void testBasicIgnoreTrimmed1() {
-        final String input = "a: bIGNOREc : ";
-        final StrTokenizer tok = new StrTokenizer(input, ':');
-        tok.setIgnoredMatcher(StrMatcher.stringMatcher("IGNORE"));
-        tok.setTrimmerMatcher(StrMatcher.trimMatcher());
-        tok.setIgnoreEmptyTokens(false);
-        tok.setEmptyTokenAsNull(true);
-        assertEquals("a", tok.next());
-        assertEquals("bc", tok.next());
-        assertNull(tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    @Test
-    public void testBasicIgnoreTrimmed2() {
-        final String input = "IGNOREaIGNORE: IGNORE bIGNOREc IGNORE : IGNORE ";
-        final StrTokenizer tok = new StrTokenizer(input, ':');
-        tok.setIgnoredMatcher(StrMatcher.stringMatcher("IGNORE"));
-        tok.setTrimmerMatcher(StrMatcher.trimMatcher());
-        tok.setIgnoreEmptyTokens(false);
-        tok.setEmptyTokenAsNull(true);
-        assertEquals("a", tok.next());
-        assertEquals("bc", tok.next());
-        assertNull(tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    @Test
-    public void testBasicIgnoreTrimmed3() {
-        final String input = "IGNOREaIGNORE: IGNORE bIGNOREc IGNORE : IGNORE ";
-        final StrTokenizer tok = new StrTokenizer(input, ':');
-        tok.setIgnoredMatcher(StrMatcher.stringMatcher("IGNORE"));
-        tok.setIgnoreEmptyTokens(false);
-        tok.setEmptyTokenAsNull(true);
-        assertEquals("a", tok.next());
-        assertEquals("  bc  ", tok.next());
-        assertEquals("  ", tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    @Test
-    public void testBasicIgnoreTrimmed4() {
-        final String input = "IGNOREaIGNORE: IGNORE 'bIGNOREc'IGNORE'd' IGNORE : IGNORE ";
-        final StrTokenizer tok = new StrTokenizer(input, ':', '\'');
-        tok.setIgnoredMatcher(StrMatcher.stringMatcher("IGNORE"));
-        tok.setTrimmerMatcher(StrMatcher.trimMatcher());
-        tok.setIgnoreEmptyTokens(false);
-        tok.setEmptyTokenAsNull(true);
-        assertEquals("a", tok.next());
-        assertEquals("bIGNOREcd", tok.next());
-        assertNull(tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    // -----------------------------------------------------------------------
-    @Test
-    public void testListArray() {
-        final String input = "a  b c";
-        final StrTokenizer tok = new StrTokenizer(input);
-        final String[] array = tok.getTokenArray();
-        final List<?> list = tok.getTokenList();
-
-        assertEquals(Arrays.asList(array), list);
-        assertEquals(3, list.size());
-    }
-
-    // -----------------------------------------------------------------------
-    private void testCSV(final String data) {
-        this.testXSVAbc(StrTokenizer.getCSVInstance(data));
-        this.testXSVAbc(StrTokenizer.getCSVInstance(data.toCharArray()));
-    }
-
-    @Test
-    public void testCSVEmpty() {
-        this.testEmpty(StrTokenizer.getCSVInstance());
-        this.testEmpty(StrTokenizer.getCSVInstance(""));
-    }
-
-    @Test
-    public void testCSVSimple() {
-        this.testCSV(CSV_SIMPLE_FIXTURE);
-    }
-
-    @Test
-    public void testCSVSimpleNeedsTrim() {
-        this.testCSV("   " + CSV_SIMPLE_FIXTURE);
-        this.testCSV("   \n\t  " + CSV_SIMPLE_FIXTURE);
-        this.testCSV("   \n  " + CSV_SIMPLE_FIXTURE + "\n\n\r");
-    }
-
-    void testEmpty(final StrTokenizer tokenizer) {
-        this.checkClone(tokenizer);
-        assertFalse(tokenizer.hasNext());
-        assertFalse(tokenizer.hasPrevious());
-        assertNull(tokenizer.nextToken());
-        assertEquals(0, tokenizer.size());
-        assertThrows(NoSuchElementException.class, () -> tokenizer.next());
-    }
-
-    @Test
-    public void testGetContent() {
-        final String input = "a   b c \"d e\" f ";
-        StrTokenizer tok = new StrTokenizer(input);
-        assertEquals(input, tok.getContent());
-
-        tok = new StrTokenizer(input.toCharArray());
-        assertEquals(input, tok.getContent());
-
-        tok = new StrTokenizer();
-        assertNull(tok.getContent());
-    }
-
     // -----------------------------------------------------------------------
     @Test
     public void testChaining() {
@@ -658,179 +564,180 @@ public class StrTokenizerTest {
 
     // -----------------------------------------------------------------------
     @Test
-    public void testConstructor_String() {
-        StrTokenizer tok = new StrTokenizer("a b");
+    public void testConstructor_charArray() {
+        StrTokenizer tok = new StrTokenizer("a b".toCharArray());
         assertEquals("a", tok.next());
         assertEquals("b", tok.next());
         assertFalse(tok.hasNext());
 
-        tok = new StrTokenizer("");
+        tok = new StrTokenizer(ArrayUtils.EMPTY_CHAR_ARRAY);
         assertFalse(tok.hasNext());
 
-        tok = new StrTokenizer((String) null);
+        tok = new StrTokenizer((char[]) null);
         assertFalse(tok.hasNext());
     }
 
     // -----------------------------------------------------------------------
     @Test
-    public void testConstructor_String_char() {
-        StrTokenizer tok = new StrTokenizer("a b", ' ');
+    public void testConstructor_charArray_char() {
+        StrTokenizer tok = new StrTokenizer("a b".toCharArray(), ' ');
         assertEquals(1, tok.getDelimiterMatcher().isMatch(" ".toCharArray(), 0, 0, 1));
         assertEquals("a", tok.next());
         assertEquals("b", tok.next());
         assertFalse(tok.hasNext());
 
-        tok = new StrTokenizer("", ' ');
+        tok = new StrTokenizer(ArrayUtils.EMPTY_CHAR_ARRAY, ' ');
         assertFalse(tok.hasNext());
 
-        tok = new StrTokenizer((String) null, ' ');
+        tok = new StrTokenizer((char[]) null, ' ');
         assertFalse(tok.hasNext());
     }
 
     // -----------------------------------------------------------------------
     @Test
-    public void testConstructor_String_char_char() {
-        StrTokenizer tok = new StrTokenizer("a b", ' ', '"');
+    public void testConstructor_charArray_char_char() {
+        StrTokenizer tok = new StrTokenizer("a b".toCharArray(), ' ', '"');
         assertEquals(1, tok.getDelimiterMatcher().isMatch(" ".toCharArray(), 0, 0, 1));
         assertEquals(1, tok.getQuoteMatcher().isMatch("\"".toCharArray(), 0, 0, 1));
         assertEquals("a", tok.next());
         assertEquals("b", tok.next());
         assertFalse(tok.hasNext());
 
-        tok = new StrTokenizer("", ' ', '"');
+        tok = new StrTokenizer(ArrayUtils.EMPTY_CHAR_ARRAY, ' ', '"');
         assertFalse(tok.hasNext());
 
-        tok = new StrTokenizer((String) null, ' ', '"');
+        tok = new StrTokenizer((char[]) null, ' ', '"');
         assertFalse(tok.hasNext());
     }
 
     // -----------------------------------------------------------------------
     @Test
-    public void testConstructor_charArray() {
-        StrTokenizer tok = new StrTokenizer("a b".toCharArray());
+    public void testConstructor_String() {
+        StrTokenizer tok = new StrTokenizer("a b");
         assertEquals("a", tok.next());
         assertEquals("b", tok.next());
         assertFalse(tok.hasNext());
 
-        tok = new StrTokenizer(ArrayUtils.EMPTY_CHAR_ARRAY);
+        tok = new StrTokenizer("");
         assertFalse(tok.hasNext());
 
-        tok = new StrTokenizer((char[]) null);
+        tok = new StrTokenizer((String) null);
         assertFalse(tok.hasNext());
     }
 
     // -----------------------------------------------------------------------
     @Test
-    public void testConstructor_charArray_char() {
-        StrTokenizer tok = new StrTokenizer("a b".toCharArray(), ' ');
+    public void testConstructor_String_char() {
+        StrTokenizer tok = new StrTokenizer("a b", ' ');
         assertEquals(1, tok.getDelimiterMatcher().isMatch(" ".toCharArray(), 0, 0, 1));
         assertEquals("a", tok.next());
         assertEquals("b", tok.next());
         assertFalse(tok.hasNext());
 
-        tok = new StrTokenizer(ArrayUtils.EMPTY_CHAR_ARRAY, ' ');
+        tok = new StrTokenizer("", ' ');
         assertFalse(tok.hasNext());
 
-        tok = new StrTokenizer((char[]) null, ' ');
+        tok = new StrTokenizer((String) null, ' ');
         assertFalse(tok.hasNext());
     }
 
     // -----------------------------------------------------------------------
     @Test
-    public void testConstructor_charArray_char_char() {
-        StrTokenizer tok = new StrTokenizer("a b".toCharArray(), ' ', '"');
+    public void testConstructor_String_char_char() {
+        StrTokenizer tok = new StrTokenizer("a b", ' ', '"');
         assertEquals(1, tok.getDelimiterMatcher().isMatch(" ".toCharArray(), 0, 0, 1));
         assertEquals(1, tok.getQuoteMatcher().isMatch("\"".toCharArray(), 0, 0, 1));
         assertEquals("a", tok.next());
         assertEquals("b", tok.next());
         assertFalse(tok.hasNext());
 
-        tok = new StrTokenizer(ArrayUtils.EMPTY_CHAR_ARRAY, ' ', '"');
+        tok = new StrTokenizer("", ' ', '"');
         assertFalse(tok.hasNext());
 
-        tok = new StrTokenizer((char[]) null, ' ', '"');
+        tok = new StrTokenizer((String) null, ' ', '"');
         assertFalse(tok.hasNext());
     }
 
     // -----------------------------------------------------------------------
+    private void testCSV(final String data) {
+        this.testXSVAbc(StrTokenizer.getCSVInstance(data));
+        this.testXSVAbc(StrTokenizer.getCSVInstance(data.toCharArray()));
+    }
+
     @Test
-    public void testReset() {
-        final StrTokenizer tok = new StrTokenizer("a b c");
-        assertEquals("a", tok.next());
-        assertEquals("b", tok.next());
-        assertEquals("c", tok.next());
-        assertFalse(tok.hasNext());
+    public void testCSVEmpty() {
+        this.testEmpty(StrTokenizer.getCSVInstance());
+        this.testEmpty(StrTokenizer.getCSVInstance(""));
+    }
 
-        tok.reset();
+    @Test
+    public void testCSVSimple() {
+        this.testCSV(CSV_SIMPLE_FIXTURE);
+    }
+
+    @Test
+    public void testCSVSimpleNeedsTrim() {
+        this.testCSV("   " + CSV_SIMPLE_FIXTURE);
+        this.testCSV("   \n\t  " + CSV_SIMPLE_FIXTURE);
+        this.testCSV("   \n  " + CSV_SIMPLE_FIXTURE + "\n\n\r");
+    }
+
+    @Test
+    public void testDelimMatcher() {
+        final String input = "a/b\\c";
+        final StrMatcher delimMatcher = new StrMatcher.CharSetMatcher(new char[] {'/', '\\'});
+
+        final StrTokenizer tok = new StrTokenizer(input, delimMatcher);
         assertEquals("a", tok.next());
         assertEquals("b", tok.next());
         assertEquals("c", tok.next());
         assertFalse(tok.hasNext());
     }
 
-    // -----------------------------------------------------------------------
     @Test
-    public void testReset_String() {
-        final StrTokenizer tok = new StrTokenizer("x x x");
-        tok.reset("d e");
-        assertEquals("d", tok.next());
-        assertEquals("e", tok.next());
-        assertFalse(tok.hasNext());
+    public void testDelimMatcherQuoteMatcher() {
+        final String input = "`a`;`b`;`c`";
+        final StrMatcher delimMatcher = new StrMatcher.CharSetMatcher(new char[] {';'});
+        final StrMatcher quoteMatcher = new StrMatcher.CharSetMatcher(new char[] {'`'});
 
-        tok.reset((String) null);
+        final StrTokenizer tok = new StrTokenizer(input, delimMatcher, quoteMatcher);
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertEquals("c", tok.next());
         assertFalse(tok.hasNext());
     }
 
-    // -----------------------------------------------------------------------
     @Test
-    public void testReset_charArray() {
-        final StrTokenizer tok = new StrTokenizer("x x x");
-
-        final char[] array = new char[] {'a', 'b', 'c'};
-        tok.reset(array);
-        assertEquals("abc", tok.next());
-        assertFalse(tok.hasNext());
+    public void testDelimString() {
+        final String input = "a##b##c";
+        final StrTokenizer tok = new StrTokenizer(input, "##");
 
-        tok.reset((char[]) null);
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertEquals("c", tok.next());
         assertFalse(tok.hasNext());
     }
 
-    // -----------------------------------------------------------------------
-    @Test
-    public void testTSV() {
-        this.testXSVAbc(StrTokenizer.getTSVInstance(TSV_SIMPLE_FIXTURE));
-        this.testXSVAbc(StrTokenizer.getTSVInstance(TSV_SIMPLE_FIXTURE.toCharArray()));
+    void testEmpty(final StrTokenizer tokenizer) {
+        this.checkClone(tokenizer);
+        assertFalse(tokenizer.hasNext());
+        assertFalse(tokenizer.hasPrevious());
+        assertNull(tokenizer.nextToken());
+        assertEquals(0, tokenizer.size());
+        assertThrows(NoSuchElementException.class, () -> tokenizer.next());
     }
 
     @Test
-    public void testTSVEmpty() {
-        this.testEmpty(StrTokenizer.getTSVInstance());
-        this.testEmpty(StrTokenizer.getTSVInstance(""));
-    }
+    public void testGetContent() {
+        final String input = "a   b c \"d e\" f ";
+        StrTokenizer tok = new StrTokenizer(input);
+        assertEquals(input, tok.getContent());
 
-    void testXSVAbc(final StrTokenizer tokenizer) {
-        this.checkClone(tokenizer);
-        assertEquals(-1, tokenizer.previousIndex());
-        assertEquals(0, tokenizer.nextIndex());
-        assertNull(tokenizer.previousToken());
-        assertEquals("A", tokenizer.nextToken());
-        assertEquals(1, tokenizer.nextIndex());
-        assertEquals("b", tokenizer.nextToken());
-        assertEquals(2, tokenizer.nextIndex());
-        assertEquals("c", tokenizer.nextToken());
-        assertEquals(3, tokenizer.nextIndex());
-        assertNull(tokenizer.nextToken());
-        assertEquals(3, tokenizer.nextIndex());
-        assertEquals("c", tokenizer.previousToken());
-        assertEquals(2, tokenizer.nextIndex());
-        assertEquals("b", tokenizer.previousToken());
-        assertEquals(1, tokenizer.nextIndex());
-        assertEquals("A", tokenizer.previousToken());
-        assertEquals(0, tokenizer.nextIndex());
-        assertNull(tokenizer.previousToken());
-        assertEquals(0, tokenizer.nextIndex());
-        assertEquals(-1, tokenizer.previousIndex());
-        assertEquals(3, tokenizer.size());
+        tok = new StrTokenizer(input.toCharArray());
+        assertEquals(input, tok.getContent());
+
+        tok = new StrTokenizer();
+        assertNull(tok.getContent());
     }
 
     @Test
@@ -862,6 +769,95 @@ public class StrTokenizerTest {
 
     // -----------------------------------------------------------------------
     @Test
+    public void testListArray() {
+        final String input = "a  b c";
+        final StrTokenizer tok = new StrTokenizer(input);
+        final String[] array = tok.getTokenArray();
+        final List<?> list = tok.getTokenList();
+
+        assertEquals(Arrays.asList(array), list);
+        assertEquals(3, list.size());
+    }
+
+    @Test
+    public void testPreviousTokenAndSetEmptyTokenAsNull() {
+        final StrTokenizer strTokenizer = StrTokenizer.getTSVInstance(" \t\n\r\f");
+        strTokenizer.setEmptyTokenAsNull(true);
+
+        assertNull(strTokenizer.previousToken());
+    }
+
+    // -----------------------------------------------------------------------
+    @Test
+    public void testReset() {
+        final StrTokenizer tok = new StrTokenizer("a b c");
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertEquals("c", tok.next());
+        assertFalse(tok.hasNext());
+
+        tok.reset();
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertEquals("c", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    // -----------------------------------------------------------------------
+    @Test
+    public void testReset_charArray() {
+        final StrTokenizer tok = new StrTokenizer("x x x");
+
+        final char[] array = new char[] {'a', 'b', 'c'};
+        tok.reset(array);
+        assertEquals("abc", tok.next());
+        assertFalse(tok.hasNext());
+
+        tok.reset((char[]) null);
+        assertFalse(tok.hasNext());
+    }
+
+    // -----------------------------------------------------------------------
+    @Test
+    public void testReset_String() {
+        final StrTokenizer tok = new StrTokenizer("x x x");
+        tok.reset("d e");
+        assertEquals("d", tok.next());
+        assertEquals("e", tok.next());
+        assertFalse(tok.hasNext());
+
+        tok.reset((String) null);
+        assertFalse(tok.hasNext());
+    }
+
+    // -----------------------------------------------------------------------
+    @Test
+    public void testStringTokenizerQuoteMatcher() {
+        final char[] chars = {'\'', 'a', 'c', '\'', 'd'};
+        final StrTokenizer tokens = new StrTokenizer(chars, StrMatcher.commaMatcher(), StrMatcher.quoteMatcher());
+        assertEquals("acd", tokens.next());
+    }
+
+    // -----------------------------------------------------------------------
+    @Test
+    public void testStringTokenizerStringMatcher() {
+        final char[] chars = {'a', 'b', 'c', 'd'};
+        final StrTokenizer tokens = new StrTokenizer(chars, "bc");
+        assertEquals("a", tokens.next());
+        assertEquals("d", tokens.next());
+    }
+
+    // -----------------------------------------------------------------------
+    @Test
+    public void testStringTokenizerStrMatcher() {
+        final char[] chars = {'a', ',', 'c'};
+        final StrTokenizer tokens = new StrTokenizer(chars, StrMatcher.commaMatcher());
+        assertEquals("a", tokens.next());
+        assertEquals("c", tokens.next());
+    }
+
+    // -----------------------------------------------------------------------
+    @Test
     public void testTokenizeSubclassInputChange() {
         final StrTokenizer tkn = new StrTokenizer("a b c d e") {
 
@@ -902,35 +898,39 @@ public class StrTokenizerTest {
 
     // -----------------------------------------------------------------------
     @Test
-    public void testStringTokenizerStringMatcher() {
-        final char[] chars = {'a', 'b', 'c', 'd'};
-        final StrTokenizer tokens = new StrTokenizer(chars, "bc");
-        assertEquals("a", tokens.next());
-        assertEquals("d", tokens.next());
-    }
-
-    // -----------------------------------------------------------------------
-    @Test
-    public void testStringTokenizerStrMatcher() {
-        final char[] chars = {'a', ',', 'c'};
-        final StrTokenizer tokens = new StrTokenizer(chars, StrMatcher.commaMatcher());
-        assertEquals("a", tokens.next());
-        assertEquals("c", tokens.next());
+    public void testTSV() {
+        this.testXSVAbc(StrTokenizer.getTSVInstance(TSV_SIMPLE_FIXTURE));
+        this.testXSVAbc(StrTokenizer.getTSVInstance(TSV_SIMPLE_FIXTURE.toCharArray()));
     }
 
-    // -----------------------------------------------------------------------
     @Test
-    public void testStringTokenizerQuoteMatcher() {
-        final char[] chars = {'\'', 'a', 'c', '\'', 'd'};
-        final StrTokenizer tokens = new StrTokenizer(chars, StrMatcher.commaMatcher(), StrMatcher.quoteMatcher());
-        assertEquals("acd", tokens.next());
+    public void testTSVEmpty() {
+        this.testEmpty(StrTokenizer.getTSVInstance());
+        this.testEmpty(StrTokenizer.getTSVInstance(""));
     }
 
-    @Test
-    public void testPreviousTokenAndSetEmptyTokenAsNull() {
-        final StrTokenizer strTokenizer = StrTokenizer.getTSVInstance(" \t\n\r\f");
-        strTokenizer.setEmptyTokenAsNull(true);
-
-        assertNull(strTokenizer.previousToken());
+    void testXSVAbc(final StrTokenizer tokenizer) {
+        this.checkClone(tokenizer);
+        assertEquals(-1, tokenizer.previousIndex());
+        assertEquals(0, tokenizer.nextIndex());
+        assertNull(tokenizer.previousToken());
+        assertEquals("A", tokenizer.nextToken());
+        assertEquals(1, tokenizer.nextIndex());
+        assertEquals("b", tokenizer.nextToken());
+        assertEquals(2, tokenizer.nextIndex());
+        assertEquals("c", tokenizer.nextToken());
+        assertEquals(3, tokenizer.nextIndex());
+        assertNull(tokenizer.nextToken());
+        assertEquals(3, tokenizer.nextIndex());
+        assertEquals("c", tokenizer.previousToken());
+        assertEquals(2, tokenizer.nextIndex());
+        assertEquals("b", tokenizer.previousToken());
+        assertEquals(1, tokenizer.nextIndex());
+        assertEquals("A", tokenizer.previousToken());
+        assertEquals(0, tokenizer.nextIndex());
+        assertNull(tokenizer.previousToken());
+        assertEquals(0, tokenizer.nextIndex());
+        assertEquals(-1, tokenizer.previousIndex());
+        assertEquals(3, tokenizer.size());
     }
 }
diff --git a/src/test/java/org/apache/commons/text/StringEscapeUtilsTest.java b/src/test/java/org/apache/commons/text/StringEscapeUtilsTest.java
index bf6b80a..e175a64 100644
--- a/src/test/java/org/apache/commons/text/StringEscapeUtilsTest.java
+++ b/src/test/java/org/apache/commons/text/StringEscapeUtilsTest.java
@@ -48,6 +48,82 @@ import org.junit.jupiter.api.Test;
 public class StringEscapeUtilsTest {
     private static final String FOO = "foo";
 
+    private static final String[][] HTML_ESCAPES = {
+            {"no escaping", "plain text", "plain text"},
+            {"no escaping", "plain text", "plain text"},
+            {"empty string", "", ""},
+            {"null", null, null},
+            {"ampersand", "bread &amp; butter", "bread & butter"},
+            {"quotes", "&quot;bread&quot; &amp; butter", "\"bread\" & butter"},
+            {"final character only", "greater than &gt;", "greater than >"},
+            {"first character only", "&lt; less than", "< less than"},
+            {"apostrophe", "Huntington's chorea", "Huntington's chorea"},
+            {"languages", "English,Fran&ccedil;ais,\u65E5\u672C\u8A9E (nihongo)",
+                "English,Fran\u00E7ais,\u65E5\u672C\u8A9E (nihongo)"},
+            {"8-bit ascii shouldn't number-escape", "\u0080\u009F", "\u0080\u009F"},
+    };
+
+    private void assertEscapeJava(final String escaped, final String original) throws IOException {
+        assertEscapeJava(escaped, original, null);
+    }
+
+    private void assertEscapeJava(final String expected, final String original, String message) throws IOException {
+        final String converted = StringEscapeUtils.escapeJava(original);
+        message = "escapeJava(String) failed" + (message == null ? "" : (": " + message));
+        assertEquals(expected, converted, message);
+
+        final StringWriter writer = new StringWriter();
+        StringEscapeUtils.ESCAPE_JAVA.translate(original, writer);
+        assertEquals(expected, writer.toString());
+    }
+
+    private void assertUnescapeJava(final String unescaped, final String original) throws IOException {
+        assertUnescapeJava(unescaped, original, null);
+    }
+
+    private void assertUnescapeJava(final String unescaped, final String original, final String message)
+            throws IOException {
+        final String expected = unescaped;
+        final String actual = StringEscapeUtils.unescapeJava(original);
+
+        assertEquals(expected, actual, "unescape(String) failed"
+                        + (message == null ? "" : (": " + message))
+                        + ": expected '" + StringEscapeUtils.escapeJava(expected)
+                        // we escape this so we can see it in the error message
+                        + "' actual '" + StringEscapeUtils.escapeJava(actual) + "'");
+
+        final StringWriter writer = new StringWriter();
+        StringEscapeUtils.UNESCAPE_JAVA.translate(original, writer);
+        assertEquals(unescaped, writer.toString());
+    }
+
+    private void checkCsvEscapeWriter(final String expected, final String value) {
+        try {
+            final StringWriter writer = new StringWriter();
+            StringEscapeUtils.ESCAPE_CSV.translate(value, writer);
+            assertEquals(expected, writer.toString());
+        } catch (final IOException e) {
+            fail("Threw: " + e);
+        }
+    }
+
+    private void checkCsvUnescapeWriter(final String expected, final String value) {
+        try {
+            final StringWriter writer = new StringWriter();
+            StringEscapeUtils.UNESCAPE_CSV.translate(value, writer);
+            assertEquals(expected, writer.toString());
+        } catch (final IOException e) {
+            fail("Threw: " + e);
+        }
+    }
+
+    @Test
+    public void testBuilder() {
+        final String result =
+                StringEscapeUtils.builder(StringEscapeUtils.ESCAPE_XML10).escape("<").append(">").toString();
+        assertEquals("&lt;>", result);
+    }
+
     @Test
     public void testConstructor() {
         assertNotNull(new StringEscapeUtils());
@@ -58,6 +134,159 @@ public class StringEscapeUtilsTest {
         assertFalse(Modifier.isFinal(StringEscapeUtils.class.getModifiers()));
     }
 
+
+    // HTML and XML
+    //--------------------------------------------------------------
+
+    @Test
+    public void testDeleteCharacter() {
+      final String deleteString = "Delete: \u007F";
+      assertEquals("Delete: \\u007F", StringEscapeUtils.escapeJson(deleteString));
+    }
+
+    @Test
+    public void testEscapeCsvString() {
+        assertEquals("foo.bar", StringEscapeUtils.escapeCsv("foo.bar"));
+        assertEquals("\"foo,bar\"", StringEscapeUtils.escapeCsv("foo,bar"));
+        assertEquals("\"foo\nbar\"", StringEscapeUtils.escapeCsv("foo\nbar"));
+        assertEquals("\"foo\rbar\"", StringEscapeUtils.escapeCsv("foo\rbar"));
+        assertEquals("\"foo\"\"bar\"", StringEscapeUtils.escapeCsv("foo\"bar"));
+        assertEquals("foo\uD84C\uDFB4bar", StringEscapeUtils.escapeCsv("foo\uD84C\uDFB4bar"));
+        assertEquals("", StringEscapeUtils.escapeCsv(""));
+        assertNull(StringEscapeUtils.escapeCsv(null));
+    }
+
+    @Test
+    public void testEscapeCsvWriter() {
+        checkCsvEscapeWriter("foo.bar", "foo.bar");
+        checkCsvEscapeWriter("\"foo,bar\"", "foo,bar");
+        checkCsvEscapeWriter("\"foo\nbar\"", "foo\nbar");
+        checkCsvEscapeWriter("\"foo\rbar\"", "foo\rbar");
+        checkCsvEscapeWriter("\"foo\"\"bar\"", "foo\"bar");
+        checkCsvEscapeWriter("foo\uD84C\uDFB4bar", "foo\uD84C\uDFB4bar");
+        checkCsvEscapeWriter("", null);
+        checkCsvEscapeWriter("", "");
+    }
+
+@Test
+public void testEscapeEcmaScript() {
+    assertNull(StringEscapeUtils.escapeEcmaScript(null));
+    try {
+        StringEscapeUtils.ESCAPE_ECMASCRIPT.translate(null, null);
+        fail("Exception expected!");
+    } catch (final IOException ex) {
+        fail("Exception expected!");
+    } catch (final IllegalArgumentException ex) {
+        // expected
+    }
+    try {
+        StringEscapeUtils.ESCAPE_ECMASCRIPT.translate("", null);
+        fail("Exception expected!");
+    } catch (final IOException ex) {
+        fail("Exception expected!");
+    } catch (final IllegalArgumentException ex) {
+        // expected
+    }
+
+    assertEquals("He didn\\'t say, \\\"stop!\\\"", StringEscapeUtils.escapeEcmaScript("He didn't say, \"stop!\""));
+    assertEquals("document.getElementById(\\\"test\\\").value = \\'<script>alert(\\'aaa\\');<\\/script>\\';",
+            StringEscapeUtils.escapeEcmaScript(
+                    "document.getElementById(\"test\").value = '<script>alert('aaa');</script>';"));
+}
+
+    /**
+     * Tests https://issues.apache.org/jira/browse/LANG-339
+     */
+    @Test
+    public void testEscapeHiragana() {
+        // Some random Japanese Unicode characters
+        final String original = "\u304B\u304C\u3068";
+        final String escaped = StringEscapeUtils.escapeHtml4(original);
+        assertEquals(original, escaped,
+                "Hiragana character Unicode behavior should not be being escaped by escapeHtml4");
+
+        final String unescaped = StringEscapeUtils.unescapeHtml4(escaped);
+
+        assertEquals(escaped, unescaped, "Hiragana character Unicode behavior has changed - expected no unescaping");
+    }
+
+    @Test
+    public void testEscapeHtml3() {
+        for (final String[] element : HTML_ESCAPES) {
+            final String message = element[0];
+            final String expected = element[1];
+            final String original = element[2];
+            assertEquals(expected, StringEscapeUtils.escapeHtml4(original), message);
+            final StringWriter sw = new StringWriter();
+            try {
+                StringEscapeUtils.ESCAPE_HTML3.translate(original, sw);
+            } catch (final IOException e) {
+                // expected
+            }
+            final String actual = original == null ? null : sw.toString();
+            assertEquals(expected, actual, message);
+        }
+    }
+
+    @Test
+        public void testEscapeHtml4() {
+            for (final String[] element : HTML_ESCAPES) {
+                final String message = element[0];
+                final String expected = element[1];
+                final String original = element[2];
+                assertEquals(expected, StringEscapeUtils.escapeHtml4(original), message);
+                final StringWriter sw = new StringWriter();
+                try {
+                    StringEscapeUtils.ESCAPE_HTML4.translate(original, sw);
+                } catch (final IOException e) {
+                    // expected
+                }
+                final String actual = original == null ? null : sw.toString();
+                assertEquals(expected, actual, message);
+            }
+        }
+
+    /**
+     * Tests // https://issues.apache.org/jira/browse/LANG-480
+     */
+    @Test
+    public void testEscapeHtmlHighUnicode() {
+        // this is the utf8 representation of the character:
+        // COUNTING ROD UNIT DIGIT THREE
+        // in Unicode
+        // codepoint: U+1D362
+        final byte[] data = {(byte) 0xF0, (byte) 0x9D, (byte) 0x8D, (byte) 0xA2};
+
+        final String original = new String(data, Charset.forName("UTF8"));
+
+        final String escaped = StringEscapeUtils.escapeHtml4(original);
+        assertEquals(original, escaped, "High Unicode should not have been escaped");
+
+        final String unescaped = StringEscapeUtils.unescapeHtml4(escaped);
+        assertEquals(original, unescaped, "High Unicode should have been unchanged");
+
+        // TODO: I think this should hold, needs further investigation
+        //        String unescapedFromEntity = StringEscapeUtils.unescapeHtml4("&#119650;");
+        //        assertEquals("High Unicode should have been unescaped", original, unescapedFromEntity);
+    }
+
+
+
+    @Test
+    public void testEscapeHtmlThree() {
+        assertNull(StringEscapeUtils.escapeHtml3(null));
+        assertEquals("a", StringEscapeUtils.escapeHtml3("a"));
+        assertEquals("&lt;b&gt;a", StringEscapeUtils.escapeHtml3("<b>a"));
+    }
+
+    @Test
+    public void testEscapeHtmlVersions() {
+        assertEquals("&Beta;", StringEscapeUtils.escapeHtml4("\u0392"));
+        assertEquals("\u0392", StringEscapeUtils.unescapeHtml4("&Beta;"));
+
+        // TODO: refine API for escaping/unescaping specific HTML versions
+    }
+
     @Test
     public void testEscapeJava() throws IOException {
         assertNull(StringEscapeUtils.escapeJava(null));
@@ -115,25 +344,11 @@ public class StringEscapeUtilsTest {
         assertEquals(expected, actual);
     }
 
-    private void assertEscapeJava(final String escaped, final String original) throws IOException {
-        assertEscapeJava(escaped, original, null);
-    }
-
-    private void assertEscapeJava(final String expected, final String original, String message) throws IOException {
-        final String converted = StringEscapeUtils.escapeJava(original);
-        message = "escapeJava(String) failed" + (message == null ? "" : (": " + message));
-        assertEquals(expected, converted, message);
-
-        final StringWriter writer = new StringWriter();
-        StringEscapeUtils.ESCAPE_JAVA.translate(original, writer);
-        assertEquals(expected, writer.toString());
-    }
-
     @Test
-    public void testUnescapeJava() throws IOException {
-        assertNull(StringEscapeUtils.unescapeJava(null));
+    public void testEscapeJson() {
+        assertNull(StringEscapeUtils.escapeJson(null));
         try {
-            StringEscapeUtils.UNESCAPE_JAVA.translate(null, null);
+            StringEscapeUtils.ESCAPE_JSON.translate(null, null);
             fail("Exception expected!");
         } catch (final IOException ex) {
             fail("Exception expected!");
@@ -141,217 +356,23 @@ public class StringEscapeUtilsTest {
             // expected
         }
         try {
-            StringEscapeUtils.UNESCAPE_JAVA.translate("", null);
+            StringEscapeUtils.ESCAPE_JSON.translate("", null);
             fail("Exception expected!");
         } catch (final IOException ex) {
             fail("Exception expected!");
         } catch (final IllegalArgumentException ex) {
             // expected
         }
-        assertThrows(RuntimeException.class, () -> StringEscapeUtils.unescapeJava("\\u02-3"));
-
-        assertUnescapeJava("", "");
-        assertUnescapeJava("test", "test");
-        assertUnescapeJava("\ntest\b", "\\ntest\\b");
-        assertUnescapeJava("\u123425foo\ntest\b", "\\u123425foo\\ntest\\b");
-        assertUnescapeJava("'\foo\teste\r", "\\'\\foo\\teste\\r");
-        assertUnescapeJava("", "\\");
-        //foo
-        assertUnescapeJava("\uABCDx", "\\uabcdx", "lowercase Unicode");
-        assertUnescapeJava("\uABCDx", "\\uABCDx", "uppercase Unicode");
-        assertUnescapeJava("\uABCD", "\\uabcd", "Unicode as final character");
-    }
-
-    private void assertUnescapeJava(final String unescaped, final String original) throws IOException {
-        assertUnescapeJava(unescaped, original, null);
-    }
 
-    private void assertUnescapeJava(final String unescaped, final String original, final String message)
-            throws IOException {
-        final String expected = unescaped;
-        final String actual = StringEscapeUtils.unescapeJava(original);
+        assertEquals("He didn't say, \\\"stop!\\\"", StringEscapeUtils.escapeJson("He didn't say, \"stop!\""));
 
-        assertEquals(expected, actual, "unescape(String) failed"
-                        + (message == null ? "" : (": " + message))
-                        + ": expected '" + StringEscapeUtils.escapeJava(expected)
-                        // we escape this so we can see it in the error message
-                        + "' actual '" + StringEscapeUtils.escapeJava(actual) + "'");
+        final String expected = "\\\"foo\\\" isn't \\\"bar\\\". specials: \\b\\r\\n\\f\\t\\\\\\/";
+        final String input = "\"foo\" isn't \"bar\". specials: \b\r\n\f\t\\/";
 
-        final StringWriter writer = new StringWriter();
-        StringEscapeUtils.UNESCAPE_JAVA.translate(original, writer);
-        assertEquals(unescaped, writer.toString());
+        assertEquals(expected, StringEscapeUtils.escapeJson(input));
     }
 
     @Test
-    public void testEscapeEcmaScript() {
-        assertNull(StringEscapeUtils.escapeEcmaScript(null));
-        try {
-            StringEscapeUtils.ESCAPE_ECMASCRIPT.translate(null, null);
-            fail("Exception expected!");
-        } catch (final IOException ex) {
-            fail("Exception expected!");
-        } catch (final IllegalArgumentException ex) {
-            // expected
-        }
-        try {
-            StringEscapeUtils.ESCAPE_ECMASCRIPT.translate("", null);
-            fail("Exception expected!");
-        } catch (final IOException ex) {
-            fail("Exception expected!");
-        } catch (final IllegalArgumentException ex) {
-            // expected
-        }
-
-        assertEquals("He didn\\'t say, \\\"stop!\\\"", StringEscapeUtils.escapeEcmaScript("He didn't say, \"stop!\""));
-        assertEquals("document.getElementById(\\\"test\\\").value = \\'<script>alert(\\'aaa\\');<\\/script>\\';",
-                StringEscapeUtils.escapeEcmaScript(
-                        "document.getElementById(\"test\").value = '<script>alert('aaa');</script>';"));
-    }
-
-
-    // HTML and XML
-    //--------------------------------------------------------------
-
-    private static final String[][] HTML_ESCAPES = {
-            {"no escaping", "plain text", "plain text"},
-            {"no escaping", "plain text", "plain text"},
-            {"empty string", "", ""},
-            {"null", null, null},
-            {"ampersand", "bread &amp; butter", "bread & butter"},
-            {"quotes", "&quot;bread&quot; &amp; butter", "\"bread\" & butter"},
-            {"final character only", "greater than &gt;", "greater than >"},
-            {"first character only", "&lt; less than", "< less than"},
-            {"apostrophe", "Huntington's chorea", "Huntington's chorea"},
-            {"languages", "English,Fran&ccedil;ais,\u65E5\u672C\u8A9E (nihongo)",
-                "English,Fran\u00E7ais,\u65E5\u672C\u8A9E (nihongo)"},
-            {"8-bit ascii shouldn't number-escape", "\u0080\u009F", "\u0080\u009F"},
-    };
-
-    @Test
-    public void testEscapeHtml3() {
-        for (final String[] element : HTML_ESCAPES) {
-            final String message = element[0];
-            final String expected = element[1];
-            final String original = element[2];
-            assertEquals(expected, StringEscapeUtils.escapeHtml4(original), message);
-            final StringWriter sw = new StringWriter();
-            try {
-                StringEscapeUtils.ESCAPE_HTML3.translate(original, sw);
-            } catch (final IOException e) {
-                // expected
-            }
-            final String actual = original == null ? null : sw.toString();
-            assertEquals(expected, actual, message);
-        }
-    }
-
-    @Test
-    public void testUnescapeHtml3() {
-        for (final String[] element : HTML_ESCAPES) {
-            final String message = element[0];
-            final String expected = element[2];
-            final String original = element[1];
-            assertEquals(expected, StringEscapeUtils.unescapeHtml3(original), message);
-
-            final StringWriter sw = new StringWriter();
-            try {
-                StringEscapeUtils.UNESCAPE_HTML3.translate(original, sw);
-            } catch (final IOException e) {
-                // expected
-            }
-            final String actual = original == null ? null : sw.toString();
-            assertEquals(expected, actual, message);
-        }
-        // \u00E7 is a cedilla (c with wiggle under)
-        // note that the test string must be 7-bit-clean (Unicode escaped) or else it will compile incorrectly
-        // on some locales
-        assertEquals("Fran\u00E7ais", StringEscapeUtils.unescapeHtml3("Fran\u00E7ais"), "funny chars pass through OK");
-
-        assertEquals("Hello&;World", StringEscapeUtils.unescapeHtml3("Hello&;World"));
-        assertEquals("Hello&#;World", StringEscapeUtils.unescapeHtml3("Hello&#;World"));
-        assertEquals("Hello&# ;World", StringEscapeUtils.unescapeHtml3("Hello&# ;World"));
-        assertEquals("Hello&##;World", StringEscapeUtils.unescapeHtml3("Hello&##;World"));
-    }
-
-@Test
-    public void testEscapeHtml4() {
-        for (final String[] element : HTML_ESCAPES) {
-            final String message = element[0];
-            final String expected = element[1];
-            final String original = element[2];
-            assertEquals(expected, StringEscapeUtils.escapeHtml4(original), message);
-            final StringWriter sw = new StringWriter();
-            try {
-                StringEscapeUtils.ESCAPE_HTML4.translate(original, sw);
-            } catch (final IOException e) {
-                // expected
-            }
-            final String actual = original == null ? null : sw.toString();
-            assertEquals(expected, actual, message);
-        }
-    }
-
-    @Test
-    public void testUnescapeHtml4() {
-        for (final String[] element : HTML_ESCAPES) {
-            final String message = element[0];
-            final String expected = element[2];
-            final String original = element[1];
-            assertEquals(expected, StringEscapeUtils.unescapeHtml4(original), message);
-
-            final StringWriter sw = new StringWriter();
-            try {
-                StringEscapeUtils.UNESCAPE_HTML4.translate(original, sw);
-            } catch (final IOException e) {
-                // expected
-            }
-            final String actual = original == null ? null : sw.toString();
-            assertEquals(expected, actual, message);
-        }
-        // \u00E7 is a cedilla (c with wiggle under)
-        // note that the test string must be 7-bit-clean (Unicode escaped) or else it will compile incorrectly
-        // on some locales
-        assertEquals("Fran\u00E7ais", StringEscapeUtils.unescapeHtml4("Fran\u00E7ais"), "funny chars pass through OK");
-
-        assertEquals("Hello&;World", StringEscapeUtils.unescapeHtml4("Hello&;World"));
-        assertEquals("Hello&#;World", StringEscapeUtils.unescapeHtml4("Hello&#;World"));
-        assertEquals("Hello&# ;World", StringEscapeUtils.unescapeHtml4("Hello&# ;World"));
-        assertEquals("Hello&##;World", StringEscapeUtils.unescapeHtml4("Hello&##;World"));
-    }
-
-    @Test
-    public void testUnescapeHexCharsHtml() {
-        // Simple easy to grok test
-        assertEquals("\u0080\u009F", StringEscapeUtils.unescapeHtml4("&#x80;&#x9F;"), "hex number unescape");
-        assertEquals("\u0080\u009F", StringEscapeUtils.unescapeHtml4("&#X80;&#X9F;"), "hex number unescape");
-        // Test all Character values:
-        for (char i = Character.MIN_VALUE; i < Character.MAX_VALUE; i++) {
-            final Character c1 = i;
-            final Character c2 = (char) (i + 1);
-            final String expected = c1.toString() + c2.toString();
-            final String escapedC1 = "&#x" + Integer.toHexString(c1) + ";";
-            final String escapedC2 = "&#x" + Integer.toHexString(c2) + ";";
-            assertEquals(expected, StringEscapeUtils.unescapeHtml4(escapedC1 + escapedC2),
-                    "hex number unescape index " + i);
-        }
-    }
-
-    @Test
-    public void testUnescapeUnknownEntity() {
-        assertEquals("&zzzz;", StringEscapeUtils.unescapeHtml4("&zzzz;"));
-    }
-
-    @Test
-    public void testEscapeHtmlVersions() {
-        assertEquals("&Beta;", StringEscapeUtils.escapeHtml4("\u0392"));
-        assertEquals("\u0392", StringEscapeUtils.unescapeHtml4("&Beta;"));
-
-        // TODO: refine API for escaping/unescaping specific HTML versions
-    }
-
-
-
-    @Test
     public void testEscapeXml10() {
         assertEquals("a&lt;b&gt;c&quot;d&apos;e&amp;f", StringEscapeUtils.escapeXml10("a<b>c\"d'e&f"));
         assertEquals("a\tb\rc\nd", StringEscapeUtils.escapeXml10("a\tb\rc\nd"),
@@ -386,18 +407,45 @@ public class StringEscapeUtilsTest {
                 "XML 1.1 should omit #xfffe | #xffff");
     }
 
+    @Test
+    public void testEscapeXSI() {
+        assertNull(null, escapeXSI(null));
+        assertEquals("He\\ didn\\'t\\ say,\\ \\\"Stop!\\\"", escapeXSI("He didn't say, \"Stop!\""));
+        assertEquals("\\\\", escapeXSI("\\"));
+        assertEquals("", escapeXSI("\n"));
+    }
+
+    @Test
+    public void testLang313() {
+        assertEquals("& &", StringEscapeUtils.unescapeHtml4("& &amp;"));
+    }
+
     /**
-     * Reverse of the above.
+     * Tests https://issues.apache.org/jira/browse/LANG-708
      *
-     * @see <a href="https://issues.apache.org/jira/browse/LANG-729">LANG-729</a>
+     * @throws IOException
+     *             if an I/O error occurs
      */
     @Test
-    public void testUnescapeXmlSupplementaryCharacters() {
-        assertEquals("\uD84C\uDFB4", StringEscapeUtils.unescapeXml("&#144308;"),
-                "Supplementary character must be represented using a single escape");
+    public void testLang708() throws IOException {
+        final byte[] inputBytes = Files.readAllBytes(Paths.get("src/test/resources/stringEscapeUtilsTestData.txt"));
+        final String input = new String(inputBytes, StandardCharsets.UTF_8);
+        final String escaped = StringEscapeUtils.escapeEcmaScript(input);
+        // just the end:
+        assertTrue(escaped.endsWith("}]"), escaped);
+        // a little more:
+        assertTrue(escaped.endsWith("\"valueCode\\\":\\\"\\\"}]"), escaped);
+    }
 
-        assertEquals("a b c \uD84C\uDFB4", StringEscapeUtils.unescapeXml("a b c &#144308;"),
-                "Supplementary characters mixed with basic characters should be decoded correctly");
+    /**
+     * Tests https://issues.apache.org/jira/browse/LANG-911
+     */
+    @Test
+    public void testLang911() {
+        final String bellsTest = "\ud83d\udc80\ud83d\udd14";
+        final String value = StringEscapeUtils.escapeJava(bellsTest);
+        final String valueTest = StringEscapeUtils.unescapeJava(value);
+        assertEquals(bellsTest, valueTest);
     }
 
     // Tests issue #38569
@@ -411,45 +459,6 @@ public class StringEscapeUtilsTest {
     }
 
     @Test
-    public void testLang313() {
-        assertEquals("& &", StringEscapeUtils.unescapeHtml4("& &amp;"));
-    }
-
-    @Test
-    public void testEscapeCsvString() {
-        assertEquals("foo.bar", StringEscapeUtils.escapeCsv("foo.bar"));
-        assertEquals("\"foo,bar\"", StringEscapeUtils.escapeCsv("foo,bar"));
-        assertEquals("\"foo\nbar\"", StringEscapeUtils.escapeCsv("foo\nbar"));
-        assertEquals("\"foo\rbar\"", StringEscapeUtils.escapeCsv("foo\rbar"));
-        assertEquals("\"foo\"\"bar\"", StringEscapeUtils.escapeCsv("foo\"bar"));
-        assertEquals("foo\uD84C\uDFB4bar", StringEscapeUtils.escapeCsv("foo\uD84C\uDFB4bar"));
-        assertEquals("", StringEscapeUtils.escapeCsv(""));
-        assertNull(StringEscapeUtils.escapeCsv(null));
-    }
-
-    @Test
-    public void testEscapeCsvWriter() {
-        checkCsvEscapeWriter("foo.bar", "foo.bar");
-        checkCsvEscapeWriter("\"foo,bar\"", "foo,bar");
-        checkCsvEscapeWriter("\"foo\nbar\"", "foo\nbar");
-        checkCsvEscapeWriter("\"foo\rbar\"", "foo\rbar");
-        checkCsvEscapeWriter("\"foo\"\"bar\"", "foo\"bar");
-        checkCsvEscapeWriter("foo\uD84C\uDFB4bar", "foo\uD84C\uDFB4bar");
-        checkCsvEscapeWriter("", null);
-        checkCsvEscapeWriter("", "");
-    }
-
-    private void checkCsvEscapeWriter(final String expected, final String value) {
-        try {
-            final StringWriter writer = new StringWriter();
-            StringEscapeUtils.ESCAPE_CSV.translate(value, writer);
-            assertEquals(expected, writer.toString());
-        } catch (final IOException e) {
-            fail("Threw: " + e);
-        }
-    }
-
-    @Test
     public void testUnescapeCsvString() {
         assertEquals("foo.bar", StringEscapeUtils.unescapeCsv("foo.bar"));
         assertEquals("foo,bar", StringEscapeUtils.unescapeCsv("\"foo,bar\""));
@@ -477,89 +486,94 @@ public class StringEscapeUtilsTest {
         checkCsvUnescapeWriter("foo.bar", "\"foo.bar\"");
     }
 
-    private void checkCsvUnescapeWriter(final String expected, final String value) {
-        try {
-            final StringWriter writer = new StringWriter();
-            StringEscapeUtils.UNESCAPE_CSV.translate(value, writer);
-            assertEquals(expected, writer.toString());
-        } catch (final IOException e) {
-            fail("Threw: " + e);
-        }
+    @Test
+    public void testUnescapeEcmaScript() {
+        assertNull(StringEscapeUtils.unescapeEcmaScript(null));
+        assertEquals("8lvc1u+6B#-I", StringEscapeUtils.unescapeEcmaScript("8lvc1u+6B#-I"));
+        assertEquals("<script src=\"build/main.bundle.js\"></script>",
+                StringEscapeUtils.unescapeEcmaScript("<script src=\"build/main.bundle.js\"></script>"));
+        assertEquals("<script src=\"build/main.bundle.js\"></script>>",
+                StringEscapeUtils.unescapeEcmaScript("<script src=\"build/main.bundle.js\"></script>>"));
     }
 
-    /**
-     * Tests // https://issues.apache.org/jira/browse/LANG-480
-     */
     @Test
-    public void testEscapeHtmlHighUnicode() {
-        // this is the utf8 representation of the character:
-        // COUNTING ROD UNIT DIGIT THREE
-        // in Unicode
-        // codepoint: U+1D362
-        final byte[] data = {(byte) 0xF0, (byte) 0x9D, (byte) 0x8D, (byte) 0xA2};
-
-        final String original = new String(data, Charset.forName("UTF8"));
-
-        final String escaped = StringEscapeUtils.escapeHtml4(original);
-        assertEquals(original, escaped, "High Unicode should not have been escaped");
-
-        final String unescaped = StringEscapeUtils.unescapeHtml4(escaped);
-        assertEquals(original, unescaped, "High Unicode should have been unchanged");
-
-        // TODO: I think this should hold, needs further investigation
-        //        String unescapedFromEntity = StringEscapeUtils.unescapeHtml4("&#119650;");
-        //        assertEquals("High Unicode should have been unescaped", original, unescapedFromEntity);
+    public void testUnescapeHexCharsHtml() {
+        // Simple easy to grok test
+        assertEquals("\u0080\u009F", StringEscapeUtils.unescapeHtml4("&#x80;&#x9F;"), "hex number unescape");
+        assertEquals("\u0080\u009F", StringEscapeUtils.unescapeHtml4("&#X80;&#X9F;"), "hex number unescape");
+        // Test all Character values:
+        for (char i = Character.MIN_VALUE; i < Character.MAX_VALUE; i++) {
+            final Character c1 = i;
+            final Character c2 = (char) (i + 1);
+            final String expected = c1.toString() + c2.toString();
+            final String escapedC1 = "&#x" + Integer.toHexString(c1) + ";";
+            final String escapedC2 = "&#x" + Integer.toHexString(c2) + ";";
+            assertEquals(expected, StringEscapeUtils.unescapeHtml4(escapedC1 + escapedC2),
+                    "hex number unescape index " + i);
+        }
     }
 
-    /**
-     * Tests https://issues.apache.org/jira/browse/LANG-339
-     */
     @Test
-    public void testEscapeHiragana() {
-        // Some random Japanese Unicode characters
-        final String original = "\u304B\u304C\u3068";
-        final String escaped = StringEscapeUtils.escapeHtml4(original);
-        assertEquals(original, escaped,
-                "Hiragana character Unicode behavior should not be being escaped by escapeHtml4");
+    public void testUnescapeHtml3() {
+        for (final String[] element : HTML_ESCAPES) {
+            final String message = element[0];
+            final String expected = element[2];
+            final String original = element[1];
+            assertEquals(expected, StringEscapeUtils.unescapeHtml3(original), message);
 
-        final String unescaped = StringEscapeUtils.unescapeHtml4(escaped);
+            final StringWriter sw = new StringWriter();
+            try {
+                StringEscapeUtils.UNESCAPE_HTML3.translate(original, sw);
+            } catch (final IOException e) {
+                // expected
+            }
+            final String actual = original == null ? null : sw.toString();
+            assertEquals(expected, actual, message);
+        }
+        // \u00E7 is a cedilla (c with wiggle under)
+        // note that the test string must be 7-bit-clean (Unicode escaped) or else it will compile incorrectly
+        // on some locales
+        assertEquals("Fran\u00E7ais", StringEscapeUtils.unescapeHtml3("Fran\u00E7ais"), "funny chars pass through OK");
 
-        assertEquals(escaped, unescaped, "Hiragana character Unicode behavior has changed - expected no unescaping");
+        assertEquals("Hello&;World", StringEscapeUtils.unescapeHtml3("Hello&;World"));
+        assertEquals("Hello&#;World", StringEscapeUtils.unescapeHtml3("Hello&#;World"));
+        assertEquals("Hello&# ;World", StringEscapeUtils.unescapeHtml3("Hello&# ;World"));
+        assertEquals("Hello&##;World", StringEscapeUtils.unescapeHtml3("Hello&##;World"));
     }
 
-    /**
-     * Tests https://issues.apache.org/jira/browse/LANG-708
-     *
-     * @throws IOException
-     *             if an I/O error occurs
-     */
     @Test
-    public void testLang708() throws IOException {
-        final byte[] inputBytes = Files.readAllBytes(Paths.get("src/test/resources/stringEscapeUtilsTestData.txt"));
-        final String input = new String(inputBytes, StandardCharsets.UTF_8);
-        final String escaped = StringEscapeUtils.escapeEcmaScript(input);
-        // just the end:
-        assertTrue(escaped.endsWith("}]"), escaped);
-        // a little more:
-        assertTrue(escaped.endsWith("\"valueCode\\\":\\\"\\\"}]"), escaped);
-    }
+    public void testUnescapeHtml4() {
+        for (final String[] element : HTML_ESCAPES) {
+            final String message = element[0];
+            final String expected = element[2];
+            final String original = element[1];
+            assertEquals(expected, StringEscapeUtils.unescapeHtml4(original), message);
 
-    /**
-     * Tests https://issues.apache.org/jira/browse/LANG-911
-     */
-    @Test
-    public void testLang911() {
-        final String bellsTest = "\ud83d\udc80\ud83d\udd14";
-        final String value = StringEscapeUtils.escapeJava(bellsTest);
-        final String valueTest = StringEscapeUtils.unescapeJava(value);
-        assertEquals(bellsTest, valueTest);
+            final StringWriter sw = new StringWriter();
+            try {
+                StringEscapeUtils.UNESCAPE_HTML4.translate(original, sw);
+            } catch (final IOException e) {
+                // expected
+            }
+            final String actual = original == null ? null : sw.toString();
+            assertEquals(expected, actual, message);
+        }
+        // \u00E7 is a cedilla (c with wiggle under)
+        // note that the test string must be 7-bit-clean (Unicode escaped) or else it will compile incorrectly
+        // on some locales
+        assertEquals("Fran\u00E7ais", StringEscapeUtils.unescapeHtml4("Fran\u00E7ais"), "funny chars pass through OK");
+
+        assertEquals("Hello&;World", StringEscapeUtils.unescapeHtml4("Hello&;World"));
+        assertEquals("Hello&#;World", StringEscapeUtils.unescapeHtml4("Hello&#;World"));
+        assertEquals("Hello&# ;World", StringEscapeUtils.unescapeHtml4("Hello&# ;World"));
+        assertEquals("Hello&##;World", StringEscapeUtils.unescapeHtml4("Hello&##;World"));
     }
 
     @Test
-    public void testEscapeJson() {
-        assertNull(StringEscapeUtils.escapeJson(null));
+    public void testUnescapeJava() throws IOException {
+        assertNull(StringEscapeUtils.unescapeJava(null));
         try {
-            StringEscapeUtils.ESCAPE_JSON.translate(null, null);
+            StringEscapeUtils.UNESCAPE_JAVA.translate(null, null);
             fail("Exception expected!");
         } catch (final IOException ex) {
             fail("Exception expected!");
@@ -567,61 +581,25 @@ public class StringEscapeUtilsTest {
             // expected
         }
         try {
-            StringEscapeUtils.ESCAPE_JSON.translate("", null);
+            StringEscapeUtils.UNESCAPE_JAVA.translate("", null);
             fail("Exception expected!");
         } catch (final IOException ex) {
             fail("Exception expected!");
         } catch (final IllegalArgumentException ex) {
             // expected
         }
+        assertThrows(RuntimeException.class, () -> StringEscapeUtils.unescapeJava("\\u02-3"));
 
-        assertEquals("He didn't say, \\\"stop!\\\"", StringEscapeUtils.escapeJson("He didn't say, \"stop!\""));
-
-        final String expected = "\\\"foo\\\" isn't \\\"bar\\\". specials: \\b\\r\\n\\f\\t\\\\\\/";
-        final String input = "\"foo\" isn't \"bar\". specials: \b\r\n\f\t\\/";
-
-        assertEquals(expected, StringEscapeUtils.escapeJson(input));
-    }
-
-    @Test
-    public void testBuilder() {
-        final String result =
-                StringEscapeUtils.builder(StringEscapeUtils.ESCAPE_XML10).escape("<").append(">").toString();
-        assertEquals("&lt;>", result);
-    }
-
-    @Test
-    public void testEscapeXSI() {
-        assertNull(null, escapeXSI(null));
-        assertEquals("He\\ didn\\'t\\ say,\\ \\\"Stop!\\\"", escapeXSI("He didn't say, \"Stop!\""));
-        assertEquals("\\\\", escapeXSI("\\"));
-        assertEquals("", escapeXSI("\n"));
-    }
-
-    @Test
-    public void testUnscapeXSI() {
-        assertNull(null, unescapeXSI(null));
-        assertEquals("\"", unescapeXSI("\\\""));
-        assertEquals("He didn't say, \"Stop!\"", unescapeXSI("He\\ didn\\'t\\ say,\\ \\\"Stop!\\\""));
-        assertEquals("\\", unescapeXSI("\\\\"));
-        assertEquals("", unescapeXSI("\\"));
-    }
-
-    @Test
-    public void testUnescapeEcmaScript() {
-        assertNull(StringEscapeUtils.unescapeEcmaScript(null));
-        assertEquals("8lvc1u+6B#-I", StringEscapeUtils.unescapeEcmaScript("8lvc1u+6B#-I"));
-        assertEquals("<script src=\"build/main.bundle.js\"></script>",
-                StringEscapeUtils.unescapeEcmaScript("<script src=\"build/main.bundle.js\"></script>"));
-        assertEquals("<script src=\"build/main.bundle.js\"></script>>",
-                StringEscapeUtils.unescapeEcmaScript("<script src=\"build/main.bundle.js\"></script>>"));
-    }
-
-    @Test
-    public void testEscapeHtmlThree() {
-        assertNull(StringEscapeUtils.escapeHtml3(null));
-        assertEquals("a", StringEscapeUtils.escapeHtml3("a"));
-        assertEquals("&lt;b&gt;a", StringEscapeUtils.escapeHtml3("<b>a"));
+        assertUnescapeJava("", "");
+        assertUnescapeJava("test", "test");
+        assertUnescapeJava("\ntest\b", "\\ntest\\b");
+        assertUnescapeJava("\u123425foo\ntest\b", "\\u123425foo\\ntest\\b");
+        assertUnescapeJava("'\foo\teste\r", "\\'\\foo\\teste\\r");
+        assertUnescapeJava("", "\\");
+        //foo
+        assertUnescapeJava("\uABCDx", "\\uabcdx", "lowercase Unicode");
+        assertUnescapeJava("\uABCDx", "\\uABCDx", "uppercase Unicode");
+        assertUnescapeJava("\uABCD", "\\uabcd", "Unicode as final character");
     }
 
     @Test
@@ -644,8 +622,30 @@ public class StringEscapeUtilsTest {
     }
 
     @Test
-    public void testDeleteCharacter() {
-      final String deleteString = "Delete: \u007F";
-      assertEquals("Delete: \\u007F", StringEscapeUtils.escapeJson(deleteString));
+    public void testUnescapeUnknownEntity() {
+        assertEquals("&zzzz;", StringEscapeUtils.unescapeHtml4("&zzzz;"));
+    }
+
+    /**
+     * Reverse of the above.
+     *
+     * @see <a href="https://issues.apache.org/jira/browse/LANG-729">LANG-729</a>
+     */
+    @Test
+    public void testUnescapeXmlSupplementaryCharacters() {
+        assertEquals("\uD84C\uDFB4", StringEscapeUtils.unescapeXml("&#144308;"),
+                "Supplementary character must be represented using a single escape");
+
+        assertEquals("a b c \uD84C\uDFB4", StringEscapeUtils.unescapeXml("a b c &#144308;"),
+                "Supplementary characters mixed with basic characters should be decoded correctly");
+    }
+
+    @Test
+    public void testUnscapeXSI() {
+        assertNull(null, unescapeXSI(null));
+        assertEquals("\"", unescapeXSI("\\\""));
+        assertEquals("He didn't say, \"Stop!\"", unescapeXSI("He\\ didn\\'t\\ say,\\ \\\"Stop!\\\""));
+        assertEquals("\\", unescapeXSI("\\\\"));
+        assertEquals("", unescapeXSI("\\"));
     }
 }
diff --git a/src/test/java/org/apache/commons/text/StringSubstitutorWithInterpolatorStringLookupTest.java b/src/test/java/org/apache/commons/text/StringSubstitutorWithInterpolatorStringLookupTest.java
index 890e94f..3212b75 100644
--- a/src/test/java/org/apache/commons/text/StringSubstitutorWithInterpolatorStringLookupTest.java
+++ b/src/test/java/org/apache/commons/text/StringSubstitutorWithInterpolatorStringLookupTest.java
@@ -32,21 +32,16 @@ import org.junit.jupiter.api.Test;
 public class StringSubstitutorWithInterpolatorStringLookupTest {
 
     @Test
-    public void testCustomMapWithDefaults() {
-        testCustomMapWithDefaults(true);
-    }
-
-    @Test
     public void testCustomFunctionWithDefaults() {
         testCustomFunctionWithDefaults(true);
     }
 
-    private void testCustomMapWithDefaults(final boolean addDefaultLookups) {
+    private void testCustomFunctionWithDefaults(final boolean addDefaultLookups) {
         final String key = "key";
         final String value = "value";
         final Map<String, String> map = new HashMap<>();
         map.put(key, value);
-        final StringLookup mapStringLookup = StringLookupFactory.INSTANCE.mapStringLookup(map);
+        final StringLookup mapStringLookup = StringLookupFactory.INSTANCE.functionStringLookup(k -> map.get(k));
         final Map<String, StringLookup> stringLookupMap = new HashMap<>();
         stringLookupMap.put("customLookup", mapStringLookup);
         final StringSubstitutor strSubst = new StringSubstitutor(
@@ -58,12 +53,22 @@ public class StringSubstitutorWithInterpolatorStringLookupTest {
         Assertions.assertEquals("value", strSubst.replace("${customLookup:key}"));
     }
 
-    private void testCustomFunctionWithDefaults(final boolean addDefaultLookups) {
+    @Test
+    public void testCustomFunctionWithoutDefaults() {
+        testCustomFunctionWithDefaults(false);
+    }
+
+    @Test
+    public void testCustomMapWithDefaults() {
+        testCustomMapWithDefaults(true);
+    }
+
+    private void testCustomMapWithDefaults(final boolean addDefaultLookups) {
         final String key = "key";
         final String value = "value";
         final Map<String, String> map = new HashMap<>();
         map.put(key, value);
-        final StringLookup mapStringLookup = StringLookupFactory.INSTANCE.functionStringLookup(k -> map.get(k));
+        final StringLookup mapStringLookup = StringLookupFactory.INSTANCE.mapStringLookup(map);
         final Map<String, StringLookup> stringLookupMap = new HashMap<>();
         stringLookupMap.put("customLookup", mapStringLookup);
         final StringSubstitutor strSubst = new StringSubstitutor(
@@ -81,11 +86,6 @@ public class StringSubstitutorWithInterpolatorStringLookupTest {
     }
 
     @Test
-    public void testCustomFunctionWithoutDefaults() {
-        testCustomFunctionWithDefaults(false);
-    }
-
-    @Test
     public void testDefaultInterpolator() {
         // Used to cut and paste into the docs.
         // @formatter:off
diff --git a/src/test/java/org/apache/commons/text/StringTokenizerTest.java b/src/test/java/org/apache/commons/text/StringTokenizerTest.java
index 675bf0d..7d1b85d 100644
--- a/src/test/java/org/apache/commons/text/StringTokenizerTest.java
+++ b/src/test/java/org/apache/commons/text/StringTokenizerTest.java
@@ -298,63 +298,82 @@ public class StringTokenizerTest {
     }
 
     @Test
-    public void testDelimString() {
-        final String input = "a##b##c";
-        final StringTokenizer tok = new StringTokenizer(input, "##");
-
+    public void testBasicEmpty1() {
+        final String input = "a  b c";
+        final StringTokenizer tok = new StringTokenizer(input);
+        tok.setIgnoreEmptyTokens(false);
         assertEquals("a", tok.next());
+        assertEquals("", tok.next());
         assertEquals("b", tok.next());
         assertEquals("c", tok.next());
         assertFalse(tok.hasNext());
     }
 
     @Test
-    public void testDelimMatcher() {
-        final String input = "a/b\\c";
-        final StringMatcher delimMatcher = StringMatcherFactory.INSTANCE.charSetMatcher('/', '\\');
-
-        final StringTokenizer tok = new StringTokenizer(input, delimMatcher);
+    public void testBasicEmpty2() {
+        final String input = "a  b c";
+        final StringTokenizer tok = new StringTokenizer(input);
+        tok.setIgnoreEmptyTokens(false);
+        tok.setEmptyTokenAsNull(true);
         assertEquals("a", tok.next());
+        assertNull(tok.next());
         assertEquals("b", tok.next());
         assertEquals("c", tok.next());
         assertFalse(tok.hasNext());
     }
 
     @Test
-    public void testDelimMatcherQuoteMatcher() {
-        final String input = "`a`;`b`;`c`";
-        final StringMatcher delimMatcher = StringMatcherFactory.INSTANCE.charSetMatcher(';');
-        final StringMatcher quoteMatcher = StringMatcherFactory.INSTANCE.charSetMatcher('`');
+    public void testBasicIgnoreTrimmed1() {
+        final String input = "a: bIGNOREc : ";
+        final StringTokenizer tok = new StringTokenizer(input, ':');
+        tok.setIgnoredMatcher(StringMatcherFactory.INSTANCE.stringMatcher("IGNORE"));
+        tok.setTrimmerMatcher(StringMatcherFactory.INSTANCE.trimMatcher());
+        tok.setIgnoreEmptyTokens(false);
+        tok.setEmptyTokenAsNull(true);
+        assertEquals("a", tok.next());
+        assertEquals("bc", tok.next());
+        assertNull(tok.next());
+        assertFalse(tok.hasNext());
+    }
 
-        final StringTokenizer tok = new StringTokenizer(input, delimMatcher, quoteMatcher);
+    @Test
+    public void testBasicIgnoreTrimmed2() {
+        final String input = "IGNOREaIGNORE: IGNORE bIGNOREc IGNORE : IGNORE ";
+        final StringTokenizer tok = new StringTokenizer(input, ':');
+        tok.setIgnoredMatcher(StringMatcherFactory.INSTANCE.stringMatcher("IGNORE"));
+        tok.setTrimmerMatcher(StringMatcherFactory.INSTANCE.trimMatcher());
+        tok.setIgnoreEmptyTokens(false);
+        tok.setEmptyTokenAsNull(true);
         assertEquals("a", tok.next());
-        assertEquals("b", tok.next());
-        assertEquals("c", tok.next());
+        assertEquals("bc", tok.next());
+        assertNull(tok.next());
         assertFalse(tok.hasNext());
     }
 
     @Test
-    public void testBasicEmpty1() {
-        final String input = "a  b c";
-        final StringTokenizer tok = new StringTokenizer(input);
+    public void testBasicIgnoreTrimmed3() {
+        final String input = "IGNOREaIGNORE: IGNORE bIGNOREc IGNORE : IGNORE ";
+        final StringTokenizer tok = new StringTokenizer(input, ':');
+        tok.setIgnoredMatcher(StringMatcherFactory.INSTANCE.stringMatcher("IGNORE"));
         tok.setIgnoreEmptyTokens(false);
+        tok.setEmptyTokenAsNull(true);
         assertEquals("a", tok.next());
-        assertEquals("", tok.next());
-        assertEquals("b", tok.next());
-        assertEquals("c", tok.next());
+        assertEquals("  bc  ", tok.next());
+        assertEquals("  ", tok.next());
         assertFalse(tok.hasNext());
     }
 
     @Test
-    public void testBasicEmpty2() {
-        final String input = "a  b c";
-        final StringTokenizer tok = new StringTokenizer(input);
+    public void testBasicIgnoreTrimmed4() {
+        final String input = "IGNOREaIGNORE: IGNORE 'bIGNOREc'IGNORE'd' IGNORE : IGNORE ";
+        final StringTokenizer tok = new StringTokenizer(input, ':', '\'');
+        tok.setIgnoredMatcher(StringMatcherFactory.INSTANCE.stringMatcher("IGNORE"));
+        tok.setTrimmerMatcher(StringMatcherFactory.INSTANCE.trimMatcher());
         tok.setIgnoreEmptyTokens(false);
         tok.setEmptyTokenAsNull(true);
         assertEquals("a", tok.next());
+        assertEquals("bIGNOREcd", tok.next());
         assertNull(tok.next());
-        assertEquals("b", tok.next());
-        assertEquals("c", tok.next());
         assertFalse(tok.hasNext());
     }
 
@@ -477,119 +496,6 @@ public class StringTokenizerTest {
         assertFalse(tok.hasNext());
     }
 
-    @Test
-    public void testBasicIgnoreTrimmed1() {
-        final String input = "a: bIGNOREc : ";
-        final StringTokenizer tok = new StringTokenizer(input, ':');
-        tok.setIgnoredMatcher(StringMatcherFactory.INSTANCE.stringMatcher("IGNORE"));
-        tok.setTrimmerMatcher(StringMatcherFactory.INSTANCE.trimMatcher());
-        tok.setIgnoreEmptyTokens(false);
-        tok.setEmptyTokenAsNull(true);
-        assertEquals("a", tok.next());
-        assertEquals("bc", tok.next());
-        assertNull(tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    @Test
-    public void testBasicIgnoreTrimmed2() {
-        final String input = "IGNOREaIGNORE: IGNORE bIGNOREc IGNORE : IGNORE ";
-        final StringTokenizer tok = new StringTokenizer(input, ':');
-        tok.setIgnoredMatcher(StringMatcherFactory.INSTANCE.stringMatcher("IGNORE"));
-        tok.setTrimmerMatcher(StringMatcherFactory.INSTANCE.trimMatcher());
-        tok.setIgnoreEmptyTokens(false);
-        tok.setEmptyTokenAsNull(true);
-        assertEquals("a", tok.next());
-        assertEquals("bc", tok.next());
-        assertNull(tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    @Test
-    public void testBasicIgnoreTrimmed3() {
-        final String input = "IGNOREaIGNORE: IGNORE bIGNOREc IGNORE : IGNORE ";
-        final StringTokenizer tok = new StringTokenizer(input, ':');
-        tok.setIgnoredMatcher(StringMatcherFactory.INSTANCE.stringMatcher("IGNORE"));
-        tok.setIgnoreEmptyTokens(false);
-        tok.setEmptyTokenAsNull(true);
-        assertEquals("a", tok.next());
-        assertEquals("  bc  ", tok.next());
-        assertEquals("  ", tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    @Test
-    public void testBasicIgnoreTrimmed4() {
-        final String input = "IGNOREaIGNORE: IGNORE 'bIGNOREc'IGNORE'd' IGNORE : IGNORE ";
-        final StringTokenizer tok = new StringTokenizer(input, ':', '\'');
-        tok.setIgnoredMatcher(StringMatcherFactory.INSTANCE.stringMatcher("IGNORE"));
-        tok.setTrimmerMatcher(StringMatcherFactory.INSTANCE.trimMatcher());
-        tok.setIgnoreEmptyTokens(false);
-        tok.setEmptyTokenAsNull(true);
-        assertEquals("a", tok.next());
-        assertEquals("bIGNOREcd", tok.next());
-        assertNull(tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    // -----------------------------------------------------------------------
-    @Test
-    public void testListArray() {
-        final String input = "a  b c";
-        final StringTokenizer tok = new StringTokenizer(input);
-        final String[] array = tok.getTokenArray();
-        final List<?> list = tok.getTokenList();
-
-        assertEquals(Arrays.asList(array), list);
-        assertEquals(3, list.size());
-    }
-
-    // -----------------------------------------------------------------------
-    private void testCSV(final String data) {
-        this.testXSVAbc(StringTokenizer.getCSVInstance(data));
-        this.testXSVAbc(StringTokenizer.getCSVInstance(data.toCharArray()));
-    }
-
-    @Test
-    public void testCSVEmpty() {
-        this.testEmpty(StringTokenizer.getCSVInstance());
-        this.testEmpty(StringTokenizer.getCSVInstance(""));
-    }
-
-    @Test
-    public void testCSVSimple() {
-        this.testCSV(CSV_SIMPLE_FIXTURE);
-    }
-
-    @Test
-    public void testCSVSimpleNeedsTrim() {
-        this.testCSV("   " + CSV_SIMPLE_FIXTURE);
-        this.testCSV("   \n\t  " + CSV_SIMPLE_FIXTURE);
-        this.testCSV("   \n  " + CSV_SIMPLE_FIXTURE + "\n\n\r");
-    }
-
-    void testEmpty(final StringTokenizer tokenizer) {
-        this.checkClone(tokenizer);
-        assertFalse(tokenizer.hasNext());
-        assertFalse(tokenizer.hasPrevious());
-        assertNull(tokenizer.nextToken());
-        assertEquals(0, tokenizer.size());
-        assertThrows(NoSuchElementException.class, () -> tokenizer.next());
-    }
-
-    @Test
-    public void testGetContent() {
-        final String input = "a   b c \"d e\" f ";
-        StringTokenizer tok = new StringTokenizer(input);
-        assertEquals(input, tok.getContent());
-
-        tok = new StringTokenizer(input.toCharArray());
-        assertEquals(input, tok.getContent());
-
-        tok = new StringTokenizer();
-        assertNull(tok.getContent());
-    }
-
     // -----------------------------------------------------------------------
     @Test
     public void testChaining() {
@@ -657,40 +563,40 @@ public class StringTokenizerTest {
 
     // -----------------------------------------------------------------------
     @Test
-    public void testConstructor_String() {
-        StringTokenizer tok = new StringTokenizer("a b");
+    public void testConstructor_charArray() {
+        StringTokenizer tok = new StringTokenizer("a b".toCharArray());
         assertEquals("a", tok.next());
         assertEquals("b", tok.next());
         assertFalse(tok.hasNext());
 
-        tok = new StringTokenizer("");
+        tok = new StringTokenizer(ArrayUtils.EMPTY_CHAR_ARRAY);
         assertFalse(tok.hasNext());
 
-        tok = new StringTokenizer((String) null);
+        tok = new StringTokenizer((char[]) null);
         assertFalse(tok.hasNext());
     }
 
     // -----------------------------------------------------------------------
     @Test
-    public void testConstructor_String_char() {
-        StringTokenizer tok = new StringTokenizer("a b", ' ');
+    public void testConstructor_charArray_char() {
+        StringTokenizer tok = new StringTokenizer("a b".toCharArray(), ' ');
         assertEquals(1, tok.getDelimiterMatcher().isMatch(" ".toCharArray(), 0, 0, 1));
         assertEquals(1, tok.getDelimiterMatcher().isMatch(" ", 0, 0, 1));
         assertEquals("a", tok.next());
         assertEquals("b", tok.next());
         assertFalse(tok.hasNext());
 
-        tok = new StringTokenizer("", ' ');
+        tok = new StringTokenizer(ArrayUtils.EMPTY_CHAR_ARRAY, ' ');
         assertFalse(tok.hasNext());
 
-        tok = new StringTokenizer((String) null, ' ');
+        tok = new StringTokenizer((char[]) null, ' ');
         assertFalse(tok.hasNext());
     }
 
     // -----------------------------------------------------------------------
     @Test
-    public void testConstructor_String_char_char() {
-        StringTokenizer tok = new StringTokenizer("a b", ' ', '"');
+    public void testConstructor_charArray_char_char() {
+        StringTokenizer tok = new StringTokenizer("a b".toCharArray(), ' ', '"');
         assertEquals(1, tok.getDelimiterMatcher().isMatch(" ".toCharArray(), 0, 0, 1));
         assertEquals(1, tok.getDelimiterMatcher().isMatch(" ", 0, 0, 1));
         assertEquals(1, tok.getQuoteMatcher().isMatch("\"".toCharArray(), 0, 0, 1));
@@ -699,49 +605,49 @@ public class StringTokenizerTest {
         assertEquals("b", tok.next());
         assertFalse(tok.hasNext());
 
-        tok = new StringTokenizer("", ' ', '"');
+        tok = new StringTokenizer(ArrayUtils.EMPTY_CHAR_ARRAY, ' ', '"');
         assertFalse(tok.hasNext());
 
-        tok = new StringTokenizer((String) null, ' ', '"');
+        tok = new StringTokenizer((char[]) null, ' ', '"');
         assertFalse(tok.hasNext());
     }
 
     // -----------------------------------------------------------------------
     @Test
-    public void testConstructor_charArray() {
-        StringTokenizer tok = new StringTokenizer("a b".toCharArray());
+    public void testConstructor_String() {
+        StringTokenizer tok = new StringTokenizer("a b");
         assertEquals("a", tok.next());
         assertEquals("b", tok.next());
         assertFalse(tok.hasNext());
 
-        tok = new StringTokenizer(ArrayUtils.EMPTY_CHAR_ARRAY);
+        tok = new StringTokenizer("");
         assertFalse(tok.hasNext());
 
-        tok = new StringTokenizer((char[]) null);
+        tok = new StringTokenizer((String) null);
         assertFalse(tok.hasNext());
     }
 
     // -----------------------------------------------------------------------
     @Test
-    public void testConstructor_charArray_char() {
-        StringTokenizer tok = new StringTokenizer("a b".toCharArray(), ' ');
+    public void testConstructor_String_char() {
+        StringTokenizer tok = new StringTokenizer("a b", ' ');
         assertEquals(1, tok.getDelimiterMatcher().isMatch(" ".toCharArray(), 0, 0, 1));
         assertEquals(1, tok.getDelimiterMatcher().isMatch(" ", 0, 0, 1));
         assertEquals("a", tok.next());
         assertEquals("b", tok.next());
         assertFalse(tok.hasNext());
 
-        tok = new StringTokenizer(ArrayUtils.EMPTY_CHAR_ARRAY, ' ');
+        tok = new StringTokenizer("", ' ');
         assertFalse(tok.hasNext());
 
-        tok = new StringTokenizer((char[]) null, ' ');
+        tok = new StringTokenizer((String) null, ' ');
         assertFalse(tok.hasNext());
     }
 
     // -----------------------------------------------------------------------
     @Test
-    public void testConstructor_charArray_char_char() {
-        StringTokenizer tok = new StringTokenizer("a b".toCharArray(), ' ', '"');
+    public void testConstructor_String_char_char() {
+        StringTokenizer tok = new StringTokenizer("a b", ' ', '"');
         assertEquals(1, tok.getDelimiterMatcher().isMatch(" ".toCharArray(), 0, 0, 1));
         assertEquals(1, tok.getDelimiterMatcher().isMatch(" ", 0, 0, 1));
         assertEquals(1, tok.getQuoteMatcher().isMatch("\"".toCharArray(), 0, 0, 1));
@@ -750,92 +656,93 @@ public class StringTokenizerTest {
         assertEquals("b", tok.next());
         assertFalse(tok.hasNext());
 
-        tok = new StringTokenizer(ArrayUtils.EMPTY_CHAR_ARRAY, ' ', '"');
+        tok = new StringTokenizer("", ' ', '"');
         assertFalse(tok.hasNext());
 
-        tok = new StringTokenizer((char[]) null, ' ', '"');
+        tok = new StringTokenizer((String) null, ' ', '"');
         assertFalse(tok.hasNext());
     }
 
     // -----------------------------------------------------------------------
+    private void testCSV(final String data) {
+        this.testXSVAbc(StringTokenizer.getCSVInstance(data));
+        this.testXSVAbc(StringTokenizer.getCSVInstance(data.toCharArray()));
+    }
+
     @Test
-    public void testReset() {
-        final StringTokenizer tok = new StringTokenizer("a b c");
-        assertEquals("a", tok.next());
-        assertEquals("b", tok.next());
-        assertEquals("c", tok.next());
-        assertFalse(tok.hasNext());
+    public void testCSVEmpty() {
+        this.testEmpty(StringTokenizer.getCSVInstance());
+        this.testEmpty(StringTokenizer.getCSVInstance(""));
+    }
 
-        tok.reset();
+    @Test
+    public void testCSVSimple() {
+        this.testCSV(CSV_SIMPLE_FIXTURE);
+    }
+
+    @Test
+    public void testCSVSimpleNeedsTrim() {
+        this.testCSV("   " + CSV_SIMPLE_FIXTURE);
+        this.testCSV("   \n\t  " + CSV_SIMPLE_FIXTURE);
+        this.testCSV("   \n  " + CSV_SIMPLE_FIXTURE + "\n\n\r");
+    }
+
+    @Test
+    public void testDelimMatcher() {
+        final String input = "a/b\\c";
+        final StringMatcher delimMatcher = StringMatcherFactory.INSTANCE.charSetMatcher('/', '\\');
+
+        final StringTokenizer tok = new StringTokenizer(input, delimMatcher);
         assertEquals("a", tok.next());
         assertEquals("b", tok.next());
         assertEquals("c", tok.next());
         assertFalse(tok.hasNext());
     }
 
-    // -----------------------------------------------------------------------
     @Test
-    public void testReset_String() {
-        final StringTokenizer tok = new StringTokenizer("x x x");
-        tok.reset("d e");
-        assertEquals("d", tok.next());
-        assertEquals("e", tok.next());
-        assertFalse(tok.hasNext());
+    public void testDelimMatcherQuoteMatcher() {
+        final String input = "`a`;`b`;`c`";
+        final StringMatcher delimMatcher = StringMatcherFactory.INSTANCE.charSetMatcher(';');
+        final StringMatcher quoteMatcher = StringMatcherFactory.INSTANCE.charSetMatcher('`');
 
-        tok.reset((String) null);
+        final StringTokenizer tok = new StringTokenizer(input, delimMatcher, quoteMatcher);
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertEquals("c", tok.next());
         assertFalse(tok.hasNext());
     }
 
-    // -----------------------------------------------------------------------
     @Test
-    public void testReset_charArray() {
-        final StringTokenizer tok = new StringTokenizer("x x x");
-
-        final char[] array = new char[] {'a', 'b', 'c' };
-        tok.reset(array);
-        assertEquals("abc", tok.next());
-        assertFalse(tok.hasNext());
+    public void testDelimString() {
+        final String input = "a##b##c";
+        final StringTokenizer tok = new StringTokenizer(input, "##");
 
-        tok.reset((char[]) null);
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertEquals("c", tok.next());
         assertFalse(tok.hasNext());
     }
 
-    // -----------------------------------------------------------------------
-    @Test
-    public void testTSV() {
-        this.testXSVAbc(StringTokenizer.getTSVInstance(TSV_SIMPLE_FIXTURE));
-        this.testXSVAbc(StringTokenizer.getTSVInstance(TSV_SIMPLE_FIXTURE.toCharArray()));
+    void testEmpty(final StringTokenizer tokenizer) {
+        this.checkClone(tokenizer);
+        assertFalse(tokenizer.hasNext());
+        assertFalse(tokenizer.hasPrevious());
+        assertNull(tokenizer.nextToken());
+        assertEquals(0, tokenizer.size());
+        assertThrows(NoSuchElementException.class, () -> tokenizer.next());
     }
 
     @Test
-    public void testTSVEmpty() {
-        this.testEmpty(StringTokenizer.getTSVInstance());
-        this.testEmpty(StringTokenizer.getTSVInstance(""));
-    }
+    public void testGetContent() {
+        final String input = "a   b c \"d e\" f ";
+        StringTokenizer tok = new StringTokenizer(input);
+        assertEquals(input, tok.getContent());
 
-    void testXSVAbc(final StringTokenizer tokenizer) {
-        this.checkClone(tokenizer);
-        assertEquals(-1, tokenizer.previousIndex());
-        assertEquals(0, tokenizer.nextIndex());
-        assertNull(tokenizer.previousToken());
-        assertEquals("A", tokenizer.nextToken());
-        assertEquals(1, tokenizer.nextIndex());
-        assertEquals("b", tokenizer.nextToken());
-        assertEquals(2, tokenizer.nextIndex());
-        assertEquals("c", tokenizer.nextToken());
-        assertEquals(3, tokenizer.nextIndex());
-        assertNull(tokenizer.nextToken());
-        assertEquals(3, tokenizer.nextIndex());
-        assertEquals("c", tokenizer.previousToken());
-        assertEquals(2, tokenizer.nextIndex());
-        assertEquals("b", tokenizer.previousToken());
-        assertEquals(1, tokenizer.nextIndex());
-        assertEquals("A", tokenizer.previousToken());
-        assertEquals(0, tokenizer.nextIndex());
-        assertNull(tokenizer.previousToken());
-        assertEquals(0, tokenizer.nextIndex());
-        assertEquals(-1, tokenizer.previousIndex());
-        assertEquals(3, tokenizer.size());
+        tok = new StringTokenizer(input.toCharArray());
+        assertEquals(input, tok.getContent());
+
+        tok = new StringTokenizer();
+        assertNull(tok.getContent());
     }
 
     @Test
@@ -867,6 +774,96 @@ public class StringTokenizerTest {
 
     // -----------------------------------------------------------------------
     @Test
+    public void testListArray() {
+        final String input = "a  b c";
+        final StringTokenizer tok = new StringTokenizer(input);
+        final String[] array = tok.getTokenArray();
+        final List<?> list = tok.getTokenList();
+
+        assertEquals(Arrays.asList(array), list);
+        assertEquals(3, list.size());
+    }
+
+    @Test
+    public void testPreviousTokenAndSetEmptyTokenAsNull() {
+        final StringTokenizer strTokenizer = StringTokenizer.getTSVInstance(" \t\n\r\f");
+        strTokenizer.setEmptyTokenAsNull(true);
+
+        assertNull(strTokenizer.previousToken());
+    }
+
+    // -----------------------------------------------------------------------
+    @Test
+    public void testReset() {
+        final StringTokenizer tok = new StringTokenizer("a b c");
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertEquals("c", tok.next());
+        assertFalse(tok.hasNext());
+
+        tok.reset();
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertEquals("c", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    // -----------------------------------------------------------------------
+    @Test
+    public void testReset_charArray() {
+        final StringTokenizer tok = new StringTokenizer("x x x");
+
+        final char[] array = new char[] {'a', 'b', 'c' };
+        tok.reset(array);
+        assertEquals("abc", tok.next());
+        assertFalse(tok.hasNext());
... 2239 lines suppressed ...