http://git-wip-us.apache.org/repos/asf/commons-text/blob/6f24aa45/src/test/java/org/apache/commons/text/StrSubstitutorTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/StrSubstitutorTest.java 
b/src/test/java/org/apache/commons/text/StrSubstitutorTest.java
new file mode 100644
index 0000000..e382691
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/StrSubstitutorTest.java
@@ -0,0 +1,740 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.text;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.commons.lang3.mutable.MutableObject;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test class for {@link StrSubstitutor}.
+ */
+public class StrSubstitutorTest {
+
+    private Map<String, String> values;
+
+    @Before
+    public void setUp() throws Exception {
+        values = new HashMap<>();
+        values.put("animal", "quick brown fox");
+        values.put("target", "lazy dog");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        values = null;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Tests simple key replace.
+     */
+    @Test
+    public void testReplaceSimple() {
+        doTestReplace("The quick brown fox jumps over the lazy dog.", "The 
${animal} jumps over the ${target}.", true);
+    }
+
+    /**
+     * Tests simple key replace.
+     */
+    @Test
+    public void testReplaceSolo() {
+        doTestReplace("quick brown fox", "${animal}", false);
+    }
+
+    /**
+     * Tests replace with no variables.
+     */
+    @Test
+    public void testReplaceNoVariables() {
+        doTestNoReplace("The balloon arrived.");
+    }
+
+    /**
+     * Tests replace with null.
+     */
+    @Test
+    public void testReplaceNull() {
+        doTestNoReplace(null);
+    }
+
+    /**
+     * Tests replace with null.
+     */
+    @Test
+    public void testReplaceEmpty() {
+        doTestNoReplace("");
+    }
+
+    /**
+     * Tests key replace changing map after initialization (not recommended).
+     */
+    @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}."));
+    }
+
+    /**
+     * Tests unknown key replace.
+     */
+    @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);
+    }
+
+    /**
+     * Tests adjacent keys.
+     */
+    @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"));
+    }
+
+    /**
+     * Tests adjacent keys.
+     */
+    @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}"));
+    }
+
+    /**
+     * Tests simple recursive replace.
+     */
+    @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);
+
+        values.put("pet", "${petCharacteristicUnknown:-lazy} dog");
+        doTestReplace("The quick brown fox jumps over the lazy dog.", "The 
${animal} jumps over the ${target}.", true);
+    }
+
+    /**
+     * Tests escaping.
+     */
+    @Test
+    public void testReplaceEscaping() {
+        doTestReplace("The ${animal} jumps over the lazy dog.", "The 
$${animal} jumps over the ${target}.", true);
+    }
+
+    /**
+     * Tests escaping.
+     */
+    @Test
+    public void testReplaceSoloEscaping() {
+        doTestReplace("${animal}", "$${animal}", false);
+    }
+
+    /**
+     * Tests complex escaping.
+     */
+    @Test
+    public void testReplaceComplexEscaping() {
+        doTestReplace("The ${quick brown fox} jumps over the lazy dog.", "The 
$${${animal}} jumps over the ${target}.", true);
+        doTestReplace("The ${quick brown fox} jumps over the lazy dog. 
${1234567890}.", "The $${${animal}} jumps over the ${target}. 
$${${undefined.number:-1234567890}}.", true);
+    }
+
+    /**
+     * Tests when no prefix or suffix.
+     */
+    @Test
+    public void testReplaceNoPrefixNoSuffix() {
+        doTestReplace("The animal jumps over the lazy dog.", "The animal jumps 
over the ${target}.", true);
+    }
+
+    /**
+     * Tests when no incomplete prefix.
+     */
+    @Test
+    public void testReplaceIncompletePrefix() {
+        doTestReplace("The {animal} jumps over the lazy dog.", "The {animal} 
jumps over the ${target}.", true);
+    }
+
+    /**
+     * 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 when suffix but no prefix.
+     */
+    @Test
+    public void testReplaceNoPrefixSuffix() {
+        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);
+    }
+
+    /**
+     * 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);
+    }
+
+    /**
+     * 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}");
+        StrSubstitutor sub = new StrSubstitutor(map);
+        try {
+            sub.replace("The ${animal} jumps over the ${target}.");
+            fail("Cyclic replacement was not detected!");
+        } catch (final IllegalStateException ex) {
+            // expected
+        }
+
+        // also check even when default value is set.
+        map.put("critterType", "${animal:-fox}");
+        sub = new StrSubstitutor(map);
+        try {
+            sub.replace("The ${animal} jumps over the ${target}.");
+            fail("Cyclic replacement was not detected!");
+        } catch (final IllegalStateException ex) {
+            // expected
+        }
+    }
+
+    /**
+     * 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 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));
+    }
+
+    /**
+     * Tests whether a variable can be replaced in a variable name.
+     */
+    @Test
+    public void testReplaceInVariable() {
+        values.put("animal.1", "fox");
+        values.put("animal.2", "mouse");
+        values.put("species", "2");
+        final StrSubstitutor sub = new StrSubstitutor(values);
+        sub.setEnableSubstitutionInVariables(true);
+        assertEquals(
+                "Wrong result (1)",
+                "The mouse jumps over the lazy dog.",
+                sub.replace("The ${animal.${species}} jumps over the 
${target}."));
+        values.put("species", "1");
+        assertEquals(
+                "Wrong result (2)",
+                "The fox jumps over the lazy dog.",
+                sub.replace("The ${animal.${species}} jumps over the 
${target}."));
+        assertEquals(
+                "Wrong result (3)",
+                "The fox jumps over the lazy dog.",
+                sub.replace("The ${unknown.animal.${unknown.species:-1}:-fox} 
jumps over the ${unknow.target:-lazy dog}."));
+    }
+
+    /**
+     * Tests whether substitution in variable names is disabled per default.
+     */
+    @Test
+    public void testReplaceInVariableDisabled() {
+        values.put("animal.1", "fox");
+        values.put("animal.2", "mouse");
+        values.put("species", "2");
+        final StrSubstitutor sub = new StrSubstitutor(values);
+        assertEquals(
+                "Wrong result (1)",
+                "The ${animal.${species}} jumps over the lazy dog.",
+                sub.replace("The ${animal.${species}} jumps over the 
${target}."));
+        assertEquals(
+                "Wrong result (2)",
+                "The ${animal.${species:-1}} jumps over the lazy dog.",
+                sub.replace("The ${animal.${species:-1}} jumps over the 
${target}."));
+    }
+
+    /**
+     * Tests complex and recursive substitution in variable names.
+     */
+    @Test
+    public void testReplaceInVariableRecursive() {
+        values.put("animal.2", "brown fox");
+        values.put("animal.1", "white mouse");
+        values.put("color", "white");
+        values.put("species.white", "1");
+        values.put("species.brown", "2");
+        final StrSubstitutor sub = new StrSubstitutor(values);
+        sub.setEnableSubstitutionInVariables(true);
+        assertEquals(
+                "Wrong result (1)",
+                "The white mouse jumps over the lazy dog.",
+                sub.replace("The ${animal.${species.${color}}} jumps over the 
${target}."));
+        assertEquals(
+                "Wrong result (2)",
+                "The brown fox jumps over the lazy dog.",
+                sub.replace("The ${animal.${species.${unknownColor:-brown}}} 
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}."));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Tests protected.
+     */
+    @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());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Tests constructor.
+     */
+    @Test
+    public void testConstructorNoArgs() {
+        final StrSubstitutor sub = new StrSubstitutor();
+        assertEquals("Hi ${name}", sub.replace("Hi ${name}"));
+    }
+
+    /**
+     * Tests constructor.
+     */
+    @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>"));
+    }
+
+    /**
+     * Tests constructor.
+     */
+    @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>"));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Tests get set.
+     */
+    @Test
+    public void testGetSetEscape() {
+        final StrSubstitutor sub = new StrSubstitutor();
+        assertEquals('$', sub.getEscapeChar());
+        sub.setEscapeChar('<');
+        assertEquals('<', sub.getEscapeChar());
+    }
+
+    /**
+     * Tests get set.
+     */
+    @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);
+        try {
+            sub.setVariablePrefix((String) null);
+            fail();
+        } catch (final IllegalArgumentException ex) {
+            // expected
+        }
+        assertTrue(sub.getVariablePrefixMatcher() instanceof 
StrMatcher.StringMatcher);
+
+        final StrMatcher matcher = StrMatcher.commaMatcher();
+        sub.setVariablePrefixMatcher(matcher);
+        assertSame(matcher, sub.getVariablePrefixMatcher());
+        try {
+            sub.setVariablePrefixMatcher((StrMatcher) null);
+            fail();
+        } catch (final IllegalArgumentException ex) {
+            // expected
+        }
+        assertSame(matcher, sub.getVariablePrefixMatcher());
+    }
+
+    /**
+     * Tests get set.
+     */
+    @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);
+        try {
+            sub.setVariableSuffix((String) null);
+            fail();
+        } catch (final IllegalArgumentException ex) {
+            // expected
+        }
+        assertTrue(sub.getVariableSuffixMatcher() instanceof 
StrMatcher.StringMatcher);
+
+        final StrMatcher matcher = StrMatcher.commaMatcher();
+        sub.setVariableSuffixMatcher(matcher);
+        assertSame(matcher, sub.getVariableSuffixMatcher());
+        try {
+            sub.setVariableSuffixMatcher((StrMatcher) null);
+            fail();
+        } catch (final IllegalArgumentException ex) {
+            // expected
+        }
+        assertSame(matcher, sub.getVariableSuffixMatcher());
+    }
+
+    /**
+     * 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());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Tests static.
+     */
+    @Test
+    public void testStaticReplace() {
+        final Map<String, String> map = new HashMap<>();
+        map.put("name", "commons");
+        assertEquals("Hi commons!", StrSubstitutor.replace("Hi ${name}!", 
map));
+    }
+
+    /**
+     * Tests static.
+     */
+    @Test
+    public void testStaticReplacePrefixSuffix() {
+        final Map<String, String> map = new HashMap<>();
+        map.put("name", "commons");
+        assertEquals("Hi commons!", StrSubstitutor.replace("Hi <name>!", map, 
"<", ">"));
+    }
+
+    /**
+     * Tests interpolation with system properties.
+     */
+    @Test
+    public void testStaticReplaceSystemProperties() {
+        final StrBuilder buf = new StrBuilder();
+        buf.append("Hi ").append(System.getProperty("user.name"));
+        buf.append(", you are working with ");
+        buf.append(System.getProperty("os.name"));
+        buf.append(", your home directory is ");
+        buf.append(System.getProperty("user.home")).append('.');
+        assertEquals(buf.toString(), 
StrSubstitutor.replaceSystemProperties("Hi ${user.name}, you are "
+            + "working with ${os.name}, your home "
+            + "directory is ${user.home}."));
+    }
+
+    /**
+     * 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
+    public void testSubstituteDefaultProperties(){
+        final String org = "${doesnotwork}";
+        System.setProperty("doesnotwork", "It works!");
+
+        // create a new Properties object with the System.getProperties as 
default
+        final Properties props = new Properties(System.getProperties());
+
+        assertEquals("It works!", StrSubstitutor.replace(org, props));
+    }
+
+    @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<>();
+        map.put("not-escaped", "value");
+
+        final StrSubstitutor sub = new StrSubstitutor(map, "${", "}", '$');
+        assertFalse(sub.isPreserveEscapes());
+        assertEquals("value ${escaped}", sub.replace(org));
+
+        sub.setPreserveEscapes(true);
+        assertTrue(sub.isPreserveEscapes());
+        assertEquals("value $${escaped}", sub.replace(org));
+    }
+
+    //-----------------------------------------------------------------------
+    private void doTestReplace(final String expectedResult, final String 
replaceTemplate, final boolean substring) {
+        final String expectedShortResult = expectedResult.substring(1, 
expectedResult.length() - 1);
+        final StrSubstitutor sub = new StrSubstitutor(values);
+
+        // 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) {
+            assertEquals(null, sub.replace((String) null));
+            assertEquals(null, sub.replace((String) null, 0, 100));
+            assertEquals(null, sub.replace((char[]) null));
+            assertEquals(null, sub.replace((char[]) null, 0, 100));
+            assertEquals(null, sub.replace((StringBuffer) null));
+            assertEquals(null, sub.replace((StringBuffer) null, 0, 100));
+            assertEquals(null, sub.replace((StrBuilder) null));
+            assertEquals(null, sub.replace((StrBuilder) null, 0, 100));
+            assertEquals(null, 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());
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/6f24aa45/src/test/java/org/apache/commons/text/StrTokenizerTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/StrTokenizerTest.java 
b/src/test/java/org/apache/commons/text/StrTokenizerTest.java
new file mode 100644
index 0000000..4b39f55
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/StrTokenizerTest.java
@@ -0,0 +1,879 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.text;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import org.apache.commons.lang3.ArrayUtils;
+
+/**
+ * Unit test for {@link StrTokenizer}.
+ */
+public class StrTokenizerTest {
+
+    private static final String CSV_SIMPLE_FIXTURE = "A,b,c";
+
+    private static final String TSV_SIMPLE_FIXTURE = "A\tb\tc";
+
+    private void checkClone(final StrTokenizer tokenizer) {
+        assertFalse(StrTokenizer.getCSVInstance() == tokenizer);
+        assertFalse(StrTokenizer.getTSVInstance() == tokenizer);
+    }
+
+    // -----------------------------------------------------------------------
+    @Test
+    public void test1() {
+
+        final String input = "a;b;c;\"d;\"\"e\";f; ; ;  ";
+        final StrTokenizer tok = new StrTokenizer(input);
+        tok.setDelimiterChar(';');
+        tok.setQuoteChar('"');
+        tok.setIgnoredMatcher(StrMatcher.trimMatcher());
+        tok.setIgnoreEmptyTokens(false);
+        final String tokens[] = tok.getTokenArray();
+
+        final String expected[] = new String[]{"a", "b", "c", "d;\"e", "f", 
"", "", "",};
+
+        assertEquals(ArrayUtils.toString(tokens), expected.length, 
tokens.length);
+        for (int i = 0; i < expected.length; i++) {
+            assertEquals("token[" + i + "] was '" + tokens[i] + "' but was 
expected to be '" + expected[i] + "'",
+                    expected[i], tokens[i]);
+        }
+
+    }
+
+    @Test
+    public void test2() {
+
+        final String input = "a;b;c ;\"d;\"\"e\";f; ; ;";
+        final StrTokenizer tok = new StrTokenizer(input);
+        tok.setDelimiterChar(';');
+        tok.setQuoteChar('"');
+        tok.setIgnoredMatcher(StrMatcher.noneMatcher());
+        tok.setIgnoreEmptyTokens(false);
+        final String tokens[] = tok.getTokenArray();
+
+        final String expected[] = new String[]{"a", "b", "c ", "d;\"e", "f", " 
", " ", "",};
+
+        assertEquals(ArrayUtils.toString(tokens), expected.length, 
tokens.length);
+        for (int i = 0; i < expected.length; i++) {
+            assertEquals("token[" + i + "] was '" + tokens[i] + "' but was 
expected to be '" + expected[i] + "'",
+                    expected[i], tokens[i]);
+        }
+
+    }
+
+    @Test
+    public void test3() {
+
+        final String input = "a;b; c;\"d;\"\"e\";f; ; ;";
+        final StrTokenizer tok = new StrTokenizer(input);
+        tok.setDelimiterChar(';');
+        tok.setQuoteChar('"');
+        tok.setIgnoredMatcher(StrMatcher.noneMatcher());
+        tok.setIgnoreEmptyTokens(false);
+        final String tokens[] = tok.getTokenArray();
+
+        final String expected[] = new String[]{"a", "b", " c", "d;\"e", "f", " 
", " ", "",};
+
+        assertEquals(ArrayUtils.toString(tokens), expected.length, 
tokens.length);
+        for (int i = 0; i < expected.length; i++) {
+            assertEquals("token[" + i + "] was '" + tokens[i] + "' but was 
expected to be '" + expected[i] + "'",
+                    expected[i], tokens[i]);
+        }
+
+    }
+
+    @Test
+    public void test4() {
+
+        final String input = "a;b; c;\"d;\"\"e\";f; ; ;";
+        final StrTokenizer tok = new StrTokenizer(input);
+        tok.setDelimiterChar(';');
+        tok.setQuoteChar('"');
+        tok.setIgnoredMatcher(StrMatcher.trimMatcher());
+        tok.setIgnoreEmptyTokens(true);
+        final String tokens[] = tok.getTokenArray();
+
+        final String expected[] = new String[]{"a", "b", "c", "d;\"e", "f",};
+
+        assertEquals(ArrayUtils.toString(tokens), expected.length, 
tokens.length);
+        for (int i = 0; i < expected.length; i++) {
+            assertEquals("token[" + i + "] was '" + tokens[i] + "' but was 
expected to be '" + expected[i] + "'",
+                    expected[i], tokens[i]);
+        }
+
+    }
+
+    @Test
+    public void test5() {
+
+        final String input = "a;b; c;\"d;\"\"e\";f; ; ;";
+        final StrTokenizer tok = new StrTokenizer(input);
+        tok.setDelimiterChar(';');
+        tok.setQuoteChar('"');
+        tok.setIgnoredMatcher(StrMatcher.trimMatcher());
+        tok.setIgnoreEmptyTokens(false);
+        tok.setEmptyTokenAsNull(true);
+        final String tokens[] = tok.getTokenArray();
+
+        final String expected[] = new String[]{"a", "b", "c", "d;\"e", "f", 
null, null, null,};
+
+        assertEquals(ArrayUtils.toString(tokens), expected.length, 
tokens.length);
+        for (int i = 0; i < expected.length; i++) {
+            assertEquals("token[" + i + "] was '" + tokens[i] + "' but was 
expected to be '" + expected[i] + "'",
+                    expected[i], tokens[i]);
+        }
+
+    }
+
+    @Test
+    public void test6() {
+
+        final String input = "a;b; c;\"d;\"\"e\";f; ; ;";
+        final StrTokenizer tok = new StrTokenizer(input);
+        tok.setDelimiterChar(';');
+        tok.setQuoteChar('"');
+        tok.setIgnoredMatcher(StrMatcher.trimMatcher());
+        tok.setIgnoreEmptyTokens(false);
+        // tok.setTreatingEmptyAsNull(true);
+        final String tokens[] = tok.getTokenArray();
+
+        final String expected[] = new String[]{"a", "b", " c", "d;\"e", "f", 
null, null, null,};
+
+        int nextCount = 0;
+        while (tok.hasNext()) {
+            tok.next();
+            nextCount++;
+        }
+
+        int prevCount = 0;
+        while (tok.hasPrevious()) {
+            tok.previous();
+            prevCount++;
+        }
+
+        assertEquals(ArrayUtils.toString(tokens), expected.length, 
tokens.length);
+
+        assertTrue("could not cycle through entire token list" + " using the 
'hasNext' and 'next' methods",
+                nextCount == expected.length);
+
+        assertTrue("could not cycle through entire token list" + " using the 
'hasPrevious' and 'previous' methods",
+                prevCount == expected.length);
+
+    }
+
+    @Test
+    public void test7() {
+
+        final String input = "a   b c \"d e\" f ";
+        final StrTokenizer tok = new StrTokenizer(input);
+        tok.setDelimiterMatcher(StrMatcher.spaceMatcher());
+        tok.setQuoteMatcher(StrMatcher.doubleQuoteMatcher());
+        tok.setIgnoredMatcher(StrMatcher.noneMatcher());
+        tok.setIgnoreEmptyTokens(false);
+        final String tokens[] = tok.getTokenArray();
+
+        final String expected[] = new String[]{"a", "", "", "b", "c", "d e", 
"f", "",};
+
+        assertEquals(ArrayUtils.toString(tokens), expected.length, 
tokens.length);
+        for (int i = 0; i < expected.length; i++) {
+            assertEquals("token[" + i + "] was '" + tokens[i] + "' but was 
expected to be '" + expected[i] + "'",
+                    expected[i], tokens[i]);
+        }
+
+    }
+
+    @Test
+    public void test8() {
+
+        final String input = "a   b c \"d e\" f ";
+        final StrTokenizer tok = new StrTokenizer(input);
+        tok.setDelimiterMatcher(StrMatcher.spaceMatcher());
+        tok.setQuoteMatcher(StrMatcher.doubleQuoteMatcher());
+        tok.setIgnoredMatcher(StrMatcher.noneMatcher());
+        tok.setIgnoreEmptyTokens(true);
+        final String tokens[] = tok.getTokenArray();
+
+        final String expected[] = new String[]{"a", "b", "c", "d e", "f",};
+
+        assertEquals(ArrayUtils.toString(tokens), expected.length, 
tokens.length);
+        for (int i = 0; i < expected.length; i++) {
+            assertEquals("token[" + i + "] was '" + tokens[i] + "' but was 
expected to be '" + expected[i] + "'",
+                    expected[i], tokens[i]);
+        }
+
+    }
+
+    @Test
+    public void testBasic1() {
+        final String input = "a  b c";
+        final StrTokenizer tok = new StrTokenizer(input);
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertEquals("c", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasic2() {
+        final String input = "a \nb\fc";
+        final StrTokenizer tok = new StrTokenizer(input);
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertEquals("c", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasic3() {
+        final String input = "a \nb\u0001\fc";
+        final StrTokenizer tok = new StrTokenizer(input);
+        assertEquals("a", tok.next());
+        assertEquals("b\u0001", tok.next());
+        assertEquals("c", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasic4() {
+        final String input = "a \"b\" c";
+        final StrTokenizer tok = new StrTokenizer(input);
+        assertEquals("a", tok.next());
+        assertEquals("\"b\"", tok.next());
+        assertEquals("c", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasic5() {
+        final String input = "a:b':c";
+        final StrTokenizer tok = new StrTokenizer(input, ':', '\'');
+        assertEquals("a", tok.next());
+        assertEquals("b'", tok.next());
+        assertEquals("c", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasicDelim1() {
+        final String input = "a:b:c";
+        final StrTokenizer tok = new StrTokenizer(input, ':');
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertEquals("c", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasicDelim2() {
+        final String input = "a:b:c";
+        final StrTokenizer tok = new StrTokenizer(input, ',');
+        assertEquals("a:b:c", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    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 testBasicEmpty2() {
+        final String input = "a  b c";
+        final StrTokenizer tok = new StrTokenizer(input);
+        tok.setIgnoreEmptyTokens(false);
+        tok.setEmptyTokenAsNull(true);
+        assertEquals("a", tok.next());
+        assertEquals(null, tok.next());
+        assertEquals("b", tok.next());
+        assertEquals("c", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasicQuoted1() {
+        final String input = "a 'b' c";
+        final StrTokenizer tok = new StrTokenizer(input, ' ', '\'');
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertEquals("c", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasicQuoted2() {
+        final String input = "a:'b':";
+        final StrTokenizer tok = new StrTokenizer(input, ':', '\'');
+        tok.setIgnoreEmptyTokens(false);
+        tok.setEmptyTokenAsNull(true);
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertEquals(null, tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasicQuoted3() {
+        final String input = "a:'b''c'";
+        final StrTokenizer tok = new StrTokenizer(input, ':', '\'');
+        tok.setIgnoreEmptyTokens(false);
+        tok.setEmptyTokenAsNull(true);
+        assertEquals("a", tok.next());
+        assertEquals("b'c", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasicQuoted4() {
+        final String input = "a: 'b' 'c' :d";
+        final StrTokenizer tok = new StrTokenizer(input, ':', '\'');
+        tok.setTrimmerMatcher(StrMatcher.trimMatcher());
+        tok.setIgnoreEmptyTokens(false);
+        tok.setEmptyTokenAsNull(true);
+        assertEquals("a", tok.next());
+        assertEquals("b c", tok.next());
+        assertEquals("d", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasicQuoted5() {
+        final String input = "a: 'b'x'c' :d";
+        final StrTokenizer tok = new StrTokenizer(input, ':', '\'');
+        tok.setTrimmerMatcher(StrMatcher.trimMatcher());
+        tok.setIgnoreEmptyTokens(false);
+        tok.setEmptyTokenAsNull(true);
+        assertEquals("a", tok.next());
+        assertEquals("bxc", tok.next());
+        assertEquals("d", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasicQuoted6() {
+        final String input = "a:'b'\"c':d";
+        final StrTokenizer tok = new StrTokenizer(input, ':');
+        tok.setQuoteMatcher(StrMatcher.quoteMatcher());
+        assertEquals("a", tok.next());
+        assertEquals("b\"c:d", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasicQuoted7() {
+        final String input = "a:\"There's a reason here\":b";
+        final StrTokenizer tok = new StrTokenizer(input, ':');
+        tok.setQuoteMatcher(StrMatcher.quoteMatcher());
+        assertEquals("a", tok.next());
+        assertEquals("There's a reason here", tok.next());
+        assertEquals("b", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasicQuotedTrimmed1() {
+        final String input = "a: 'b' :";
+        final StrTokenizer tok = new StrTokenizer(input, ':', '\'');
+        tok.setTrimmerMatcher(StrMatcher.trimMatcher());
+        tok.setIgnoreEmptyTokens(false);
+        tok.setEmptyTokenAsNull(true);
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertEquals(null, tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasicTrimmed1() {
+        final String input = "a: b :  ";
+        final StrTokenizer tok = new StrTokenizer(input, ':');
+        tok.setTrimmerMatcher(StrMatcher.trimMatcher());
+        tok.setIgnoreEmptyTokens(false);
+        tok.setEmptyTokenAsNull(true);
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertEquals(null, tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasicTrimmed2() {
+        final String input = "a:  b  :";
+        final StrTokenizer tok = new StrTokenizer(input, ':');
+        tok.setTrimmerMatcher(StrMatcher.stringMatcher("  "));
+        tok.setIgnoreEmptyTokens(false);
+        tok.setEmptyTokenAsNull(true);
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertEquals(null, tok.next());
+        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());
+        assertEquals(null, 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());
+        assertEquals(null, 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());
+        assertEquals(null, 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());
+        assertEquals(null, tokenizer.nextToken());
+        assertEquals(0, tokenizer.size());
+        try {
+            tokenizer.next();
+            fail();
+        } catch (final NoSuchElementException ex) {}
+    }
+
+    @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();
+        assertEquals(null, tok.getContent());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testChaining() {
+        final StrTokenizer tok = new StrTokenizer();
+        assertEquals(tok, tok.reset());
+        assertEquals(tok, tok.reset(""));
+        assertEquals(tok, tok.reset(new char[0]));
+        assertEquals(tok, tok.setDelimiterChar(' '));
+        assertEquals(tok, tok.setDelimiterString(" "));
+        assertEquals(tok, tok.setDelimiterMatcher(null));
+        assertEquals(tok, tok.setQuoteChar(' '));
+        assertEquals(tok, tok.setQuoteMatcher(null));
+        assertEquals(tok, tok.setIgnoredChar(' '));
+        assertEquals(tok, tok.setIgnoredMatcher(null));
+        assertEquals(tok, tok.setTrimmerMatcher(null));
+        assertEquals(tok, tok.setEmptyTokenAsNull(false));
+        assertEquals(tok, tok.setIgnoreEmptyTokens(false));
+    }
+
+    /**
+     * Tests that the {@link StrTokenizer#clone()} clone method catches {@link 
CloneNotSupportedException} and returns
+     * <code>null</code>.
+     */
+    @Test
+    public void testCloneNotSupportedException() {
+        final Object notCloned = new StrTokenizer() {
+            @Override
+            Object cloneReset() throws CloneNotSupportedException {
+                throw new CloneNotSupportedException("test");
+            }
+        }.clone();
+        assertNull(notCloned);
+    }
+
+    @Test
+    public void testCloneNull() {
+        final StrTokenizer tokenizer = new StrTokenizer((char[]) null);
+        // Start sanity check
+        assertEquals(null, tokenizer.nextToken());
+        tokenizer.reset();
+        assertEquals(null, tokenizer.nextToken());
+        // End sanity check
+        final StrTokenizer clonedTokenizer = (StrTokenizer) tokenizer.clone();
+        tokenizer.reset();
+        assertEquals(null, tokenizer.nextToken());
+        assertEquals(null, clonedTokenizer.nextToken());
+    }
+
+    @Test
+    public void testCloneReset() {
+        final char[] input = new char[]{'a'};
+        final StrTokenizer tokenizer = new StrTokenizer(input);
+        // Start sanity check
+        assertEquals("a", tokenizer.nextToken());
+        tokenizer.reset(input);
+        assertEquals("a", tokenizer.nextToken());
+        // End sanity check
+        final StrTokenizer clonedTokenizer = (StrTokenizer) tokenizer.clone();
+        input[0] = 'b';
+        tokenizer.reset(input);
+        assertEquals("b", tokenizer.nextToken());
+        assertEquals("a", clonedTokenizer.nextToken());
+    }
+  
+    // -----------------------------------------------------------------------
+    @Test
+    public void testConstructor_String() {
+        StrTokenizer tok = new StrTokenizer("a b");
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertFalse(tok.hasNext());
+        
+        tok = new StrTokenizer("");
+        assertFalse(tok.hasNext());
+        
+        tok = new StrTokenizer((String) null);
+        assertFalse(tok.hasNext());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    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("", ' ');
+        assertFalse(tok.hasNext());
+        
+        tok = new StrTokenizer((String) null, ' ');
+        assertFalse(tok.hasNext());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    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("", ' ', '"');
+        assertFalse(tok.hasNext());
+        
+        tok = new StrTokenizer((String) null, ' ', '"');
+        assertFalse(tok.hasNext());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    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(new char[0]);
+        assertFalse(tok.hasNext());
+        
+        tok = new StrTokenizer((char[]) null);
+        assertFalse(tok.hasNext());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    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(new char[0], ' ');
+        assertFalse(tok.hasNext());
+        
+        tok = new StrTokenizer((char[]) null, ' ');
+        assertFalse(tok.hasNext());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    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(new char[0], ' ', '"');
+        assertFalse(tok.hasNext());
+        
+        tok = new StrTokenizer((char[]) null, ' ', '"');
+        assertFalse(tok.hasNext());
+    }
+
+    //-----------------------------------------------------------------------
+    @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_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 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 testTSV() {
+        this.testXSVAbc(StrTokenizer.getTSVInstance(TSV_SIMPLE_FIXTURE));
+        
this.testXSVAbc(StrTokenizer.getTSVInstance(TSV_SIMPLE_FIXTURE.toCharArray()));
+    }
+
+    @Test
+    public void testTSVEmpty() {
+        this.testEmpty(StrTokenizer.getTSVInstance());
+        this.testEmpty(StrTokenizer.getTSVInstance(""));
+    }
+
+    void testXSVAbc(final StrTokenizer tokenizer) {
+        this.checkClone(tokenizer);
+        assertEquals(-1, tokenizer.previousIndex());
+        assertEquals(0, tokenizer.nextIndex());
+        assertEquals(null, 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());
+        assertEquals(null, 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());
+        assertEquals(null, tokenizer.previousToken());
+        assertEquals(0, tokenizer.nextIndex());
+        assertEquals(-1, tokenizer.previousIndex());
+        assertEquals(3, tokenizer.size());
+    }
+
+    @Test
+    public void testIteration() {
+        final StrTokenizer tkn = new StrTokenizer("a b c");
+        assertFalse(tkn.hasPrevious());
+        try {
+            tkn.previous();
+            fail();
+        } catch (final NoSuchElementException ex) {}
+        assertTrue(tkn.hasNext());
+        
+        assertEquals("a", tkn.next());
+        try {
+            tkn.remove();
+            fail();
+        } catch (final UnsupportedOperationException ex) {}
+        try {
+            tkn.set("x");
+            fail();
+        } catch (final UnsupportedOperationException ex) {}
+        try {
+            tkn.add("y");
+            fail();
+        } catch (final UnsupportedOperationException ex) {}
+        assertTrue(tkn.hasPrevious());
+        assertTrue(tkn.hasNext());
+        
+        assertEquals("b", tkn.next());
+        assertTrue(tkn.hasPrevious());
+        assertTrue(tkn.hasNext());
+        
+        assertEquals("c", tkn.next());
+        assertTrue(tkn.hasPrevious());
+        assertFalse(tkn.hasNext());
+        
+        try {
+            tkn.next();
+            fail();
+        } catch (final NoSuchElementException ex) {}
+        assertTrue(tkn.hasPrevious());
+        assertFalse(tkn.hasNext());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testTokenizeSubclassInputChange() {
+        final StrTokenizer tkn = new StrTokenizer("a b c d e") {
+            @Override
+            protected List<String> tokenize(final char[] chars, final int 
offset, final int count) {
+                return super.tokenize("w x y z".toCharArray(), 2, 5);
+            }
+        };
+        assertEquals("x", tkn.next());
+        assertEquals("y", tkn.next());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testTokenizeSubclassOutputChange() {
+        final StrTokenizer tkn = new StrTokenizer("a b c") {
+            @Override
+            protected List<String> tokenize(final char[] chars, final int 
offset, final int count) {
+                final List<String> list = super.tokenize(chars, offset, count);
+                Collections.reverse(list);
+                return list;
+            }
+        };
+        assertEquals("c", tkn.next());
+        assertEquals("b", tkn.next());
+        assertEquals("a", tkn.next());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testToString() {
+        final StrTokenizer tkn = new StrTokenizer("a b c d e");
+        assertEquals("StrTokenizer[not tokenized yet]", tkn.toString());
+        tkn.next();
+        assertEquals("StrTokenizer[a, b, c, d, e]", tkn.toString());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/6f24aa45/src/test/java/org/apache/commons/text/WordUtilsTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/WordUtilsTest.java 
b/src/test/java/org/apache/commons/text/WordUtilsTest.java
new file mode 100644
index 0000000..6b57072
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/WordUtilsTest.java
@@ -0,0 +1,421 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Modifier;
+
+import org.apache.commons.lang3.SystemUtils;
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link WordUtils} class.
+ */
+public class WordUtilsTest {
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testConstructor() {
+        assertNotNull(new WordUtils());
+        final Constructor<?>[] cons = 
WordUtils.class.getDeclaredConstructors();
+        assertEquals(1, cons.length);
+        assertTrue(Modifier.isPublic(cons[0].getModifiers()));
+        assertTrue(Modifier.isPublic(WordUtils.class.getModifiers()));
+        assertFalse(Modifier.isFinal(WordUtils.class.getModifiers()));
+    }
+    
+    //-----------------------------------------------------------------------
+    @Test
+    public void testWrap_StringInt() {
+        assertEquals(null, WordUtils.wrap(null, 20));
+        assertEquals(null, WordUtils.wrap(null, -1));
+        
+        assertEquals("", WordUtils.wrap("", 20));
+        assertEquals("", WordUtils.wrap("", -1));
+        
+        // normal
+        final String systemNewLine = SystemUtils.LINE_SEPARATOR;
+        String input = "Here is one line of text that is going to be wrapped 
after 20 columns.";
+        String expected = "Here is one line of" + systemNewLine + "text that 
is going" 
+            + systemNewLine + "to be wrapped after" + systemNewLine + "20 
columns.";
+        assertEquals(expected, WordUtils.wrap(input, 20));
+        
+        // long word at end
+        input = "Click here to jump to the commons website - 
http://commons.apache.org";;
+        expected = "Click here to jump" + systemNewLine + "to the commons" + 
systemNewLine 
+            + "website -" + systemNewLine + "http://commons.apache.org";;
+        assertEquals(expected, WordUtils.wrap(input, 20));
+        
+        // long word in middle
+        input = "Click here, http://commons.apache.org, to jump to the commons 
website";
+        expected = "Click here," + systemNewLine + 
"http://commons.apache.org,"; + systemNewLine 
+            + "to jump to the" + systemNewLine + "commons website";
+        assertEquals(expected, WordUtils.wrap(input, 20));
+
+        // leading spaces on a new line are stripped
+        // trailing spaces are not stripped
+        input = "word1             word2                        word3";
+        expected = "word1  " + systemNewLine + "word2  " + systemNewLine + 
"word3";
+        assertEquals(expected, WordUtils.wrap(input, 7));
+    }
+    
+    @Test
+    public void testWrap_StringIntStringBoolean() {
+        assertEquals(null, WordUtils.wrap(null, 20, "\n", false));
+        assertEquals(null, WordUtils.wrap(null, 20, "\n", true));
+        assertEquals(null, WordUtils.wrap(null, 20, null, true));
+        assertEquals(null, WordUtils.wrap(null, 20, null, false));
+        assertEquals(null, WordUtils.wrap(null, -1, null, true));
+        assertEquals(null, WordUtils.wrap(null, -1, null, false));
+        
+        assertEquals("", WordUtils.wrap("", 20, "\n", false));
+        assertEquals("", WordUtils.wrap("", 20, "\n", true));
+        assertEquals("", WordUtils.wrap("", 20, null, false));
+        assertEquals("", WordUtils.wrap("", 20, null, true));
+        assertEquals("", WordUtils.wrap("", -1, null, false));
+        assertEquals("", WordUtils.wrap("", -1, null, true));
+        
+        // normal
+        String input = "Here is one line of text that is going to be wrapped 
after 20 columns.";
+        String expected = "Here is one line of\ntext that is going\nto be 
wrapped after\n20 columns.";
+        assertEquals(expected, WordUtils.wrap(input, 20, "\n", false));
+        assertEquals(expected, WordUtils.wrap(input, 20, "\n", true));
+
+        // unusual newline char
+        input = "Here is one line of text that is going to be wrapped after 20 
columns.";
+        expected = "Here is one line of<br />text that is going<br />to be 
wrapped after<br />20 columns.";
+        assertEquals(expected, WordUtils.wrap(input, 20, "<br />", false));
+        assertEquals(expected, WordUtils.wrap(input, 20, "<br />", true));
+
+        // short line length
+        input = "Here is one line";
+        expected = "Here\nis one\nline";
+        assertEquals(expected, WordUtils.wrap(input, 6, "\n", false));
+        expected = "Here\nis\none\nline";
+        assertEquals(expected, WordUtils.wrap(input, 2, "\n", false));
+        assertEquals(expected, WordUtils.wrap(input, -1, "\n", false));
+
+        // system newline char
+        final String systemNewLine = SystemUtils.LINE_SEPARATOR;
+        input = "Here is one line of text that is going to be wrapped after 20 
columns.";
+        expected = "Here is one line of" + systemNewLine + "text that is 
going" + systemNewLine 
+            + "to be wrapped after" + systemNewLine + "20 columns.";
+        assertEquals(expected, WordUtils.wrap(input, 20, null, false));
+        assertEquals(expected, WordUtils.wrap(input, 20, null, true));
+
+        // with extra spaces
+        input = " Here:  is  one  line  of  text  that  is  going  to  be  
wrapped  after  20  columns.";
+        expected = "Here:  is  one  line\nof  text  that  is \ngoing  to  be 
\nwrapped  after  20 \ncolumns.";
+        assertEquals(expected, WordUtils.wrap(input, 20, "\n", false));
+        assertEquals(expected, WordUtils.wrap(input, 20, "\n", true));
+        
+        // with tab
+        input = "Here is\tone line of text that is going to be wrapped after 
20 columns.";
+        expected = "Here is\tone line of\ntext that is going\nto be wrapped 
after\n20 columns.";
+        assertEquals(expected, WordUtils.wrap(input, 20, "\n", false));
+        assertEquals(expected, WordUtils.wrap(input, 20, "\n", true));
+        
+        // with tab at wrapColumn
+        input = "Here is one line of\ttext that is going to be wrapped after 
20 columns.";
+        expected = "Here is one line\nof\ttext that is\ngoing to be 
wrapped\nafter 20 columns.";
+        assertEquals(expected, WordUtils.wrap(input, 20, "\n", false));
+        assertEquals(expected, WordUtils.wrap(input, 20, "\n", true));
+        
+        // difference because of long word
+        input = "Click here to jump to the commons website - 
http://commons.apache.org";;
+        expected = "Click here to jump\nto the commons\nwebsite 
-\nhttp://commons.apache.org";;
+        assertEquals(expected, WordUtils.wrap(input, 20, "\n", false));
+        expected = "Click here to jump\nto the commons\nwebsite 
-\nhttp://commons.apach\ne.org";;
+        assertEquals(expected, WordUtils.wrap(input, 20, "\n", true));
+        
+        // difference because of long word in middle
+        input = "Click here, http://commons.apache.org, to jump to the commons 
website";
+        expected = "Click here,\nhttp://commons.apache.org,\nto jump to 
the\ncommons website";
+        assertEquals(expected, WordUtils.wrap(input, 20, "\n", false));
+        expected = "Click here,\nhttp://commons.apach\ne.org, to jump to\nthe 
commons website";
+        assertEquals(expected, WordUtils.wrap(input, 20, "\n", true));
+    }
+
+    @Test
+    public void testWrap_StringIntStringBooleanString() {
+
+        //no changes test
+        String input = "flammable/inflammable";
+        String expected = "flammable/inflammable";
+        assertEquals(expected, WordUtils.wrap(input, 30, "\n", false, "/"));
+
+        // wrap on / and small width
+        expected = "flammable\ninflammable";
+        assertEquals(expected, WordUtils.wrap(input, 2, "\n", false, "/"));
+
+        // wrap long words on / 1
+        expected = "flammable\ninflammab\nle";
+        assertEquals(expected, WordUtils.wrap(input, 9, "\n", true, "/"));
+
+        // wrap long words on / 2
+        expected = "flammable\ninflammable";
+        assertEquals(expected, WordUtils.wrap(input, 15, "\n", true, "/"));
+
+        // wrap long words on / 3
+        input = "flammableinflammable";
+        expected = "flammableinflam\nmable";
+        assertEquals(expected, WordUtils.wrap(input, 15, "\n", true, "/"));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testCapitalize_String() {
+        assertEquals(null, WordUtils.capitalize(null));
+        assertEquals("", WordUtils.capitalize(""));
+        assertEquals("  ", WordUtils.capitalize("  "));
+        
+        assertEquals("I", WordUtils.capitalize("I") );
+        assertEquals("I", WordUtils.capitalize("i") );
+        assertEquals("I Am Here 123", WordUtils.capitalize("i am here 123") );
+        assertEquals("I Am Here 123", WordUtils.capitalize("I Am Here 123") );
+        assertEquals("I Am HERE 123", WordUtils.capitalize("i am HERE 123") );
+        assertEquals("I AM HERE 123", WordUtils.capitalize("I AM HERE 123") );
+    }
+    
+    @Test
+    public void testCapitalizeWithDelimiters_String() {
+        assertEquals(null, WordUtils.capitalize(null, null));
+        assertEquals("", WordUtils.capitalize("", new char[0]));
+        assertEquals("  ", WordUtils.capitalize("  ", new char[0]));
+        
+        char[] chars = new char[] { '-', '+', ' ', '@' };
+        assertEquals("I", WordUtils.capitalize("I", chars) );
+        assertEquals("I", WordUtils.capitalize("i", chars) );
+        assertEquals("I-Am Here+123", WordUtils.capitalize("i-am here+123", 
chars) );
+        assertEquals("I Am+Here-123", WordUtils.capitalize("I Am+Here-123", 
chars) );
+        assertEquals("I+Am-HERE 123", WordUtils.capitalize("i+am-HERE 123", 
chars) );
+        assertEquals("I-AM HERE+123", WordUtils.capitalize("I-AM HERE+123", 
chars) );
+        chars = new char[] {'.'};
+        assertEquals("I aM.Fine", WordUtils.capitalize("i aM.fine", chars) );
+        assertEquals("I Am.fine", WordUtils.capitalize("i am.fine", null) );
+    }
+
+    @Test
+    public void testCapitalizeFully_String() {
+        assertEquals(null, WordUtils.capitalizeFully(null));
+        assertEquals("", WordUtils.capitalizeFully(""));
+        assertEquals("  ", WordUtils.capitalizeFully("  "));
+        
+        assertEquals("I", WordUtils.capitalizeFully("I") );
+        assertEquals("I", WordUtils.capitalizeFully("i") );
+        assertEquals("I Am Here 123", WordUtils.capitalizeFully("i am here 
123") );
+        assertEquals("I Am Here 123", WordUtils.capitalizeFully("I Am Here 
123") );
+        assertEquals("I Am Here 123", WordUtils.capitalizeFully("i am HERE 
123") );
+        assertEquals("I Am Here 123", WordUtils.capitalizeFully("I AM HERE 
123") );
+    }
+    
+    @Test
+    public void testCapitalizeFullyWithDelimiters_String() {
+        assertEquals(null, WordUtils.capitalizeFully(null, null));
+        assertEquals("", WordUtils.capitalizeFully("", new char[0]));
+        assertEquals("  ", WordUtils.capitalizeFully("  ", new char[0]));
+        
+        char[] chars = new char[] { '-', '+', ' ', '@' };
+        assertEquals("I", WordUtils.capitalizeFully("I", chars) );
+        assertEquals("I", WordUtils.capitalizeFully("i", chars) );
+        assertEquals("I-Am Here+123", WordUtils.capitalizeFully("i-am 
here+123", chars) );
+        assertEquals("I Am+Here-123", WordUtils.capitalizeFully("I 
Am+Here-123", chars) );
+        assertEquals("I+Am-Here 123", WordUtils.capitalizeFully("i+am-HERE 
123", chars) );
+        assertEquals("I-Am Here+123", WordUtils.capitalizeFully("I-AM 
HERE+123", chars) );
+        chars = new char[] {'.'};
+        assertEquals("I am.Fine", WordUtils.capitalizeFully("i aM.fine", 
chars) );
+        assertEquals("I Am.fine", WordUtils.capitalizeFully("i am.fine", null) 
);
+    }
+
+    @Test
+    public void testContainsAllWords_StringString() {
+        assertFalse(WordUtils.containsAllWords(null, (String) null));
+        assertFalse(WordUtils.containsAllWords(null, ""));
+        assertFalse(WordUtils.containsAllWords(null, "ab"));
+
+        assertFalse(WordUtils.containsAllWords("", (String) null));
+        assertFalse(WordUtils.containsAllWords("", ""));
+        assertFalse(WordUtils.containsAllWords("", "ab"));
+
+        assertFalse(WordUtils.containsAllWords("foo", (String) null));
+        assertFalse(WordUtils.containsAllWords("bar", ""));
+        assertFalse(WordUtils.containsAllWords("zzabyycdxx", "by"));
+        assertTrue(WordUtils.containsAllWords("lorem ipsum dolor sit amet", 
"ipsum", "lorem", "dolor"));
+        assertFalse(WordUtils.containsAllWords("lorem ipsum dolor sit amet", 
"ipsum", null, "lorem", "dolor"));
+        assertFalse(WordUtils.containsAllWords("lorem ipsum null dolor sit 
amet", "ipsum", null, "lorem", "dolor"));
+        assertFalse(WordUtils.containsAllWords("ab", "b"));
+        assertFalse(WordUtils.containsAllWords("ab", "z"));
+    }
+
+    @Test
+    public void testUncapitalize_String() {
+        assertEquals(null, WordUtils.uncapitalize(null));
+        assertEquals("", WordUtils.uncapitalize(""));
+        assertEquals("  ", WordUtils.uncapitalize("  "));
+        
+        assertEquals("i", WordUtils.uncapitalize("I") );
+        assertEquals("i", WordUtils.uncapitalize("i") );
+        assertEquals("i am here 123", WordUtils.uncapitalize("i am here 123") 
);
+        assertEquals("i am here 123", WordUtils.uncapitalize("I Am Here 123") 
);
+        assertEquals("i am hERE 123", WordUtils.uncapitalize("i am HERE 123") 
);
+        assertEquals("i aM hERE 123", WordUtils.uncapitalize("I AM HERE 123") 
);
+    }
+    
+    @Test
+    public void testUncapitalizeWithDelimiters_String() {
+        assertEquals(null, WordUtils.uncapitalize(null, null));
+        assertEquals("", WordUtils.uncapitalize("", new char[0]));
+        assertEquals("  ", WordUtils.uncapitalize("  ", new char[0]));
+        
+        char[] chars = new char[] { '-', '+', ' ', '@' };
+        assertEquals("i", WordUtils.uncapitalize("I", chars) );
+        assertEquals("i", WordUtils.uncapitalize("i", chars) );
+        assertEquals("i am-here+123", WordUtils.uncapitalize("i am-here+123", 
chars) );
+        assertEquals("i+am here-123", WordUtils.uncapitalize("I+Am Here-123", 
chars) );
+        assertEquals("i-am+hERE 123", WordUtils.uncapitalize("i-am+HERE 123", 
chars) );
+        assertEquals("i aM-hERE+123", WordUtils.uncapitalize("I AM-HERE+123", 
chars) );
+        chars = new char[] {'.'};
+        assertEquals("i AM.fINE", WordUtils.uncapitalize("I AM.FINE", chars) );
+        assertEquals("i aM.FINE", WordUtils.uncapitalize("I AM.FINE", null) );
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testInitials_String() {
+        assertEquals(null, WordUtils.initials(null));
+        assertEquals("", WordUtils.initials(""));
+        assertEquals("", WordUtils.initials("  "));
+
+        assertEquals("I", WordUtils.initials("I"));
+        assertEquals("i", WordUtils.initials("i"));
+        assertEquals("BJL", WordUtils.initials("Ben John Lee"));
+        assertEquals("BJL", WordUtils.initials("   Ben \n   John\tLee\t"));
+        assertEquals("BJ", WordUtils.initials("Ben J.Lee"));
+        assertEquals("BJ.L", WordUtils.initials(" Ben   John  . Lee"));
+        assertEquals("iah1", WordUtils.initials("i am here 123"));
+    }
+
+    // -----------------------------------------------------------------------
+    @Test
+    public void testInitials_String_charArray() {
+        char[] array = null;
+        assertEquals(null, WordUtils.initials(null, array));
+        assertEquals("", WordUtils.initials("", array));
+        assertEquals("", WordUtils.initials("  ", array));
+        assertEquals("I", WordUtils.initials("I", array));
+        assertEquals("i", WordUtils.initials("i", array));
+        assertEquals("S", WordUtils.initials("SJC", array));
+        assertEquals("BJL", WordUtils.initials("Ben John Lee", array));
+        assertEquals("BJL", WordUtils.initials("   Ben \n   John\tLee\t", 
array));
+        assertEquals("BJ", WordUtils.initials("Ben J.Lee", array));
+        assertEquals("BJ.L", WordUtils.initials(" Ben   John  . Lee", array));
+        assertEquals("KO", WordUtils.initials("Kay O'Murphy", array));
+        assertEquals("iah1", WordUtils.initials("i am here 123", array));
+        
+        array = new char[0];
+        assertEquals(null, WordUtils.initials(null, array));
+        assertEquals("", WordUtils.initials("", array));
+        assertEquals("", WordUtils.initials("  ", array));
+        assertEquals("", WordUtils.initials("I", array));
+        assertEquals("", WordUtils.initials("i", array));
+        assertEquals("", WordUtils.initials("SJC", array));
+        assertEquals("", WordUtils.initials("Ben John Lee", array));
+        assertEquals("", WordUtils.initials("   Ben \n   John\tLee\t", array));
+        assertEquals("", WordUtils.initials("Ben J.Lee", array));
+        assertEquals("", WordUtils.initials(" Ben   John  . Lee", array));
+        assertEquals("", WordUtils.initials("Kay O'Murphy", array));
+        assertEquals("", WordUtils.initials("i am here 123", array));
+        
+        array = " ".toCharArray();
+        assertEquals(null, WordUtils.initials(null, array));
+        assertEquals("", WordUtils.initials("", array));
+        assertEquals("", WordUtils.initials("  ", array));
+        assertEquals("I", WordUtils.initials("I", array));
+        assertEquals("i", WordUtils.initials("i", array));
+        assertEquals("S", WordUtils.initials("SJC", array));
+        assertEquals("BJL", WordUtils.initials("Ben John Lee", array));
+        assertEquals("BJ", WordUtils.initials("Ben J.Lee", array));
+        assertEquals("B\nJ", WordUtils.initials("   Ben \n   John\tLee\t", 
array));
+        assertEquals("BJ.L", WordUtils.initials(" Ben   John  . Lee", array));
+        assertEquals("KO", WordUtils.initials("Kay O'Murphy", array));
+        assertEquals("iah1", WordUtils.initials("i am here 123", array));
+        
+        array = " .".toCharArray();
+        assertEquals(null, WordUtils.initials(null, array));
+        assertEquals("", WordUtils.initials("", array));
+        assertEquals("", WordUtils.initials("  ", array));
+        assertEquals("I", WordUtils.initials("I", array));
+        assertEquals("i", WordUtils.initials("i", array));
+        assertEquals("S", WordUtils.initials("SJC", array));
+        assertEquals("BJL", WordUtils.initials("Ben John Lee", array));
+        assertEquals("BJL", WordUtils.initials("Ben J.Lee", array));
+        assertEquals("BJL", WordUtils.initials(" Ben   John  . Lee", array));
+        assertEquals("KO", WordUtils.initials("Kay O'Murphy", array));
+        assertEquals("iah1", WordUtils.initials("i am here 123", array));
+        
+        array = " .'".toCharArray();
+        assertEquals(null, WordUtils.initials(null, array));
+        assertEquals("", WordUtils.initials("", array));
+        assertEquals("", WordUtils.initials("  ", array));
+        assertEquals("I", WordUtils.initials("I", array));
+        assertEquals("i", WordUtils.initials("i", array));
+        assertEquals("S", WordUtils.initials("SJC", array));
+        assertEquals("BJL", WordUtils.initials("Ben John Lee", array));
+        assertEquals("BJL", WordUtils.initials("Ben J.Lee", array));
+        assertEquals("BJL", WordUtils.initials(" Ben   John  . Lee", array));
+        assertEquals("KOM", WordUtils.initials("Kay O'Murphy", array));
+        assertEquals("iah1", WordUtils.initials("i am here 123", array));
+        
+        array = "SIJo1".toCharArray();
+        assertEquals(null, WordUtils.initials(null, array));
+        assertEquals("", WordUtils.initials("", array));
+        assertEquals(" ", WordUtils.initials("  ", array));
+        assertEquals("", WordUtils.initials("I", array));
+        assertEquals("i", WordUtils.initials("i", array));
+        assertEquals("C", WordUtils.initials("SJC", array));
+        assertEquals("Bh", WordUtils.initials("Ben John Lee", array));
+        assertEquals("B.", WordUtils.initials("Ben J.Lee", array));
+        assertEquals(" h", WordUtils.initials(" Ben   John  . Lee", array));
+        assertEquals("K", WordUtils.initials("Kay O'Murphy", array));
+        assertEquals("i2", WordUtils.initials("i am here 123", array));
+    }
+
+    // -----------------------------------------------------------------------
+    @Test
+    public void testSwapCase_String() {
+        assertEquals(null, WordUtils.swapCase(null));
+        assertEquals("", WordUtils.swapCase(""));
+        assertEquals("  ", WordUtils.swapCase("  "));
+        
+        assertEquals("i", WordUtils.swapCase("I") );
+        assertEquals("I", WordUtils.swapCase("i") );
+        assertEquals("I AM HERE 123", WordUtils.swapCase("i am here 123") );
+        assertEquals("i aM hERE 123", WordUtils.swapCase("I Am Here 123") );
+        assertEquals("I AM here 123", WordUtils.swapCase("i am HERE 123") );
+        assertEquals("i am here 123", WordUtils.swapCase("I AM HERE 123") );
+
+        final String test = "This String contains a TitleCase character: 
\u01C8";
+        final String expect = "tHIS sTRING CONTAINS A tITLEcASE CHARACTER: 
\u01C9";
+        assertEquals(expect, WordUtils.swapCase(test));
+    }
+
+}

Reply via email to