http://git-wip-us.apache.org/repos/asf/commons-text/blob/6f24aa45/src/test/java/org/apache/commons/text/ExtendedMessageFormatTest.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/commons/text/ExtendedMessageFormatTest.java 
b/src/test/java/org/apache/commons/text/ExtendedMessageFormatTest.java
new file mode 100644
index 0000000..6b91643
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/ExtendedMessageFormatTest.java
@@ -0,0 +1,484 @@
+/*
+ * 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 org.junit.Before;
+import static org.junit.Assert.*;
+import static org.apache.commons.lang3.JavaVersion.JAVA_1_4;
+
+import java.text.ChoiceFormat;
+import java.text.DateFormat;
+import java.text.FieldPosition;
+import java.text.Format;
+import java.text.MessageFormat;
+import java.text.NumberFormat;
+import java.text.ParsePosition;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.commons.lang3.SystemUtils;
+
+/**
+ * Test case for {@link ExtendedMessageFormat}.
+ *
+ * @since 2.4
+ */
+public class ExtendedMessageFormatTest {
+
+    private final Map<String, FormatFactory> registry = new HashMap<>();
+
+    @Before
+    public void setUp() throws Exception {
+        registry.put("lower", new LowerCaseFormatFactory());
+        registry.put("upper", new UpperCaseFormatFactory());
+    }
+
+    /**
+     * Test extended formats.
+     */
+    @Test
+    public void testExtendedFormats() {
+        final String pattern = "Lower: {0,lower} Upper: {1,upper}";
+        final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, 
registry);
+        assertPatternsEqual("TOPATTERN", pattern, emf.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 Bug LANG-477 - out of memory error with escaped quote
+     */
+    @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"}));
+    }
+
+    /**
+     * 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(emf.format(new Object[] {"there", 3, "great"}), "Hi 
there, got 3, GREAT!");
+    }
+
+    /**
+     * Test Bug LANG-948 - Exception while using ExtendedMessageFormat and 
escaping braces
+     */
+    @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 extended and built in formats.
+     */
+    @Test
+    public void testExtendedAndBuiltInFormats() {
+        final Calendar cal = Calendar.getInstance();
+        cal.set(2007, Calendar.JANUARY, 23, 18, 33, 05);
+        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());
+            expected.append(" DOB: ");
+            expected.append(df.format(args[1]));
+            expected.append(" Salary: ");
+            expected.append(nf.format(args[2]));
+            assertPatternsEqual("pattern comparison for locale " + locale, 
expectedPattern, emf.toPattern());
+            assertEquals(String.valueOf(locale), expected.toString(), 
emf.format(args));
+        }
+    }
+
+//    /**
+//     * Test extended formats with choice format.
+//     *
+//     * NOTE: FAILING - currently sub-formats not supported
+//     */
+//    public void testExtendedWithChoiceFormat() {
+//        String pattern = "Choice: {0,choice,1.0#{1,lower}|2.0#{1,upper}}";
+//        ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, 
registry);
+//        assertPatterns(null, pattern, emf.toPattern());
+//        try {
+//            assertEquals("one", emf.format(new Object[] {Integer.valueOf(1), 
"ONE"}));
+//            assertEquals("TWO", emf.format(new Object[] {Integer.valueOf(2), 
"two"}));
+//        } catch (IllegalArgumentException e) {
+//            // currently sub-formats not supported
+//        }
+//    }
+
+//    /**
+//     * Test mixed extended and built-in formats with choice format.
+//     *
+//     * NOTE: FAILING - currently sub-formats not supported
+//     */
+//    public void testExtendedAndBuiltInWithChoiceFormat() {
+//        String pattern = "Choice: {0,choice,1.0#{0} {1,lower} 
{2,number}|2.0#{0} {1,upper} {2,number,currency}}";
+//        Object[] lowArgs  = new Object[] {Integer.valueOf(1), "Low",  
Double.valueOf("1234.56")};
+//        Object[] highArgs = new Object[] {Integer.valueOf(2), "High", 
Double.valueOf("9876.54")};
+//        Locale[] availableLocales = ChoiceFormat.getAvailableLocales();
+//        Locale[] testLocales = new Locale[availableLocales.length + 1];
+//        testLocales[0] = null;
+//        System.arraycopy(availableLocales, 0, testLocales, 1, 
availableLocales.length);
+//        for (int i = 0; i < testLocales.length; i++) {
+//            NumberFormat nf = null;
+//            NumberFormat cf = null;
+//            ExtendedMessageFormat emf = null;
+//            if (testLocales[i] == null) {
+//                nf = NumberFormat.getNumberInstance();
+//                cf = NumberFormat.getCurrencyInstance();
+//                emf = new ExtendedMessageFormat(pattern, registry);
+//            } else {
+//                nf = NumberFormat.getNumberInstance(testLocales[i]);
+//                cf = NumberFormat.getCurrencyInstance(testLocales[i]);
+//                emf = new ExtendedMessageFormat(pattern, testLocales[i], 
registry);
+//            }
+//            assertPatterns(null, pattern, emf.toPattern());
+//            try {
+//                String lowExpected = lowArgs[0] + " low "    + 
nf.format(lowArgs[2]);
+//                String highExpected = highArgs[0] + " HIGH "  + 
cf.format(highArgs[2]);
+//                assertEquals(lowExpected,  emf.format(lowArgs));
+//                assertEquals(highExpected, emf.format(highArgs));
+//            } catch (IllegalArgumentException e) {
+//                // currently sub-formats not supported
+//            }
+//        }
+//    }
+
+    /**
+     * Test the built in choice format.
+     */
+    @Test
+    public void testBuiltInChoiceFormat() {
+        final Object[] values = new Number[] {Integer.valueOf(1), 
Double.valueOf("2.2"), Double.valueOf("1234.5")};
+        String choicePattern = null;
+        final Locale[] availableLocales = ChoiceFormat.getAvailableLocales();
+
+        choicePattern = "{0,choice,1#One|2#Two|3#Many {0,number}}";
+        for (final Object value : values) {
+            checkBuiltInFormat(value + ": " + choicePattern, new Object[] 
{value}, availableLocales);
+        }
+
+        choicePattern = "{0,choice,1#''One''|2#\"Two\"|3#''{Many}'' 
{0,number}}";
+        for (final Object value : values) {
+            checkBuiltInFormat(value + ": " + choicePattern, new Object[] 
{value}, availableLocales);
+        }
+    }
+
+    /**
+     * Test the built in date/time formats
+     */
+    @Test
+    public void testBuiltInDateTimeFormat() {
+        final Calendar cal = Calendar.getInstance();
+        cal.set(2007, Calendar.JANUARY, 23, 18, 33, 05);
+        final Object[] args = new Object[] {cal.getTime()};
+        final Locale[] availableLocales = DateFormat.getAvailableLocales();
+
+        checkBuiltInFormat("1: {0,date,short}",    args, availableLocales);
+        checkBuiltInFormat("2: {0,date,medium}",   args, availableLocales);
+        checkBuiltInFormat("3: {0,date,long}",     args, availableLocales);
+        checkBuiltInFormat("4: {0,date,full}",     args, availableLocales);
+        checkBuiltInFormat("5: {0,date,d MMM yy}", args, availableLocales);
+        checkBuiltInFormat("6: {0,time,short}",    args, availableLocales);
+        checkBuiltInFormat("7: {0,time,medium}",   args, availableLocales);
+        checkBuiltInFormat("8: {0,time,long}",     args, availableLocales);
+        checkBuiltInFormat("9: {0,time,full}",     args, availableLocales);
+        checkBuiltInFormat("10: {0,time,HH:mm}",   args, availableLocales);
+        checkBuiltInFormat("11: {0,date}",         args, availableLocales);
+        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("overridden date,short format", 
dateDefault.format(args), dateShort.format(args));
+            assertEquals("overridden date,short pattern", pattern, 
dateShort.toPattern());
+        }
+    }
+
+    /**
+     * Test the built in number formats.
+     */
+    @Test
+    public void testBuiltInNumberFormat() {
+        final Object[] args = new Object[] {Double.valueOf("6543.21")};
+        final Locale[] availableLocales = NumberFormat.getAvailableLocales();
+        checkBuiltInFormat("1: {0,number}",            args, availableLocales);
+        checkBuiltInFormat("2: {0,number,integer}",    args, availableLocales);
+        checkBuiltInFormat("3: {0,number,currency}",   args, availableLocales);
+        checkBuiltInFormat("4: {0,number,percent}",    args, availableLocales);
+        checkBuiltInFormat("5: {0,number,00000.000}",  args, availableLocales);
+    }
+
+    /**
+     * 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);
+
+        ExtendedMessageFormat other = null;
+
+        // Same object
+        assertTrue("same, equals()",   emf.equals(emf));
+        assertTrue("same, hashcode()", emf.hashCode() == emf.hashCode());
+
+        // Equal Object
+        other = new ExtendedMessageFormat(pattern, Locale.US, fmtRegistry);
+        assertTrue("equal, equals()",   emf.equals(other));
+        assertTrue("equal, hashcode()", emf.hashCode() == other.hashCode());
+
+        // Different Class
+        other = new OtherExtendedMessageFormat(pattern, Locale.US, 
fmtRegistry);
+        assertFalse("class, equals()",  emf.equals(other));
+        assertTrue("class, hashcode()", emf.hashCode() == other.hashCode()); 
// same hashcode
+        
+        // Different pattern
+        other = new ExtendedMessageFormat("X" + pattern, Locale.US, 
fmtRegistry);
+        assertFalse("pattern, equals()",   emf.equals(other));
+        assertFalse("pattern, hashcode()", emf.hashCode() == other.hashCode());
+
+        // Different registry
+        other = new ExtendedMessageFormat(pattern, Locale.US, otherRegitry);
+        assertFalse("registry, equals()",   emf.equals(other));
+        assertFalse("registry, hashcode()", emf.hashCode() == 
other.hashCode());
+
+        // Different Locale
+        other = new ExtendedMessageFormat(pattern, Locale.FRANCE, fmtRegistry);
+        assertFalse("locale, equals()",  emf.equals(other));
+        assertTrue("locale, hashcode()", emf.hashCode() == other.hashCode()); 
// same hashcode
+    }
+
+    /**
+     * Test a built in format for the specified Locales, plus 
<code>null</code> 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);
+    }
+
+    /**
+     * Test a built in format for the specified Locales, plus 
<code>null</code> 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);
+        }
+    }
+
+    /**
+     * 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
+     */
+    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("format "    + buffer.toString(), mf.format(args), 
emf.format(args));
+        assertPatternsEqual("toPattern " + buffer.toString(), mf.toPattern(),  
emf.toPattern());
+    }
+
+    //can't trust what MessageFormat does with toPattern() pre 1.4:
+    private void assertPatternsEqual(final String message, final String 
expected, final String actual) {
+        if (SystemUtils.isJavaVersionAtLeast(JAVA_1_4)) {
+            assertEquals(message, expected, actual);
+        }
+    }
+
+    /**
+     * 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;
+    }
+
+    // ------------------------ 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());
+        }
+        @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;
+
+        @Override
+        public StringBuffer format(final Object obj, final StringBuffer 
toAppendTo, final FieldPosition pos) {
+            return toAppendTo.append(((String)obj).toUpperCase());
+        }
+        @Override
+        public Object parseObject(final String source, final ParsePosition 
pos) {throw new UnsupportedOperationException();}
+    }
+
+
+    // ------------------------ 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;
+        }
+    }
+    /**
+     * {@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;
+        }
+    }
+    /**
+     * {@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);
+        }
+    }
+
+    /**
+     * Alternative ExtendedMessageFormat impl.
+     */
+    private static class OtherExtendedMessageFormat extends 
ExtendedMessageFormat {
+        private static final long serialVersionUID = 1L;
+
+        public OtherExtendedMessageFormat(final String pattern, final Locale 
locale,
+                final Map<String, ? extends FormatFactory> registry) {
+            super(pattern, locale, registry);
+        }
+        
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/6f24aa45/src/test/java/org/apache/commons/text/FormattableUtilsTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/FormattableUtilsTest.java 
b/src/test/java/org/apache/commons/text/FormattableUtilsTest.java
new file mode 100644
index 0000000..d23dba6
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/FormattableUtilsTest.java
@@ -0,0 +1,115 @@
+/*
+ * 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 java.util.FormattableFlags.LEFT_JUSTIFY;
+import static org.junit.Assert.assertEquals;
+
+import java.util.Formatter;
+
+import org.junit.Test;
+
+/**
+ * Unit tests {@link FormattableUtils}.
+ */
+public class FormattableUtilsTest {
+
+    @Test
+    public void testDefaultAppend() {
+        assertEquals("foo", FormattableUtils.append("foo", new Formatter(), 0, 
-1, -1).toString());
+        assertEquals("fo", FormattableUtils.append("foo", new Formatter(), 0, 
-1, 2).toString());
+        assertEquals(" foo", FormattableUtils.append("foo", new Formatter(), 
0, 4, -1).toString());
+        assertEquals("   foo", FormattableUtils.append("foo", new Formatter(), 
0, 6, -1).toString());
+        assertEquals(" fo", FormattableUtils.append("foo", new Formatter(), 0, 
3, 2).toString());
+        assertEquals("   fo", FormattableUtils.append("foo", new Formatter(), 
0, 5, 2).toString());
+        assertEquals("foo ", FormattableUtils.append("foo", new Formatter(), 
LEFT_JUSTIFY, 4, -1).toString());
+        assertEquals("foo   ", FormattableUtils.append("foo", new Formatter(), 
LEFT_JUSTIFY, 6, -1).toString());
+        assertEquals("fo ", FormattableUtils.append("foo", new Formatter(), 
LEFT_JUSTIFY, 3, 2).toString());
+        assertEquals("fo   ", FormattableUtils.append("foo", new Formatter(), 
LEFT_JUSTIFY, 5, 2).toString());
+    }
+
+    @Test
+    public void testAlternatePadCharacter() {
+        final char pad='_';
+        assertEquals("foo", FormattableUtils.append("foo", new Formatter(), 0, 
-1, -1, pad).toString());
+        assertEquals("fo", FormattableUtils.append("foo", new Formatter(), 0, 
-1, 2, pad).toString());
+        assertEquals("_foo", FormattableUtils.append("foo", new Formatter(), 
0, 4, -1, pad).toString());
+        assertEquals("___foo", FormattableUtils.append("foo", new Formatter(), 
0, 6, -1, pad).toString());
+        assertEquals("_fo", FormattableUtils.append("foo", new Formatter(), 0, 
3, 2, pad).toString());
+        assertEquals("___fo", FormattableUtils.append("foo", new Formatter(), 
0, 5, 2, pad).toString());
+        assertEquals("foo_", FormattableUtils.append("foo", new Formatter(), 
LEFT_JUSTIFY, 4, -1, pad).toString());
+        assertEquals("foo___", FormattableUtils.append("foo", new Formatter(), 
LEFT_JUSTIFY, 6, -1, pad).toString());
+        assertEquals("fo_", FormattableUtils.append("foo", new Formatter(), 
LEFT_JUSTIFY, 3, 2, pad).toString());
+        assertEquals("fo___", FormattableUtils.append("foo", new Formatter(), 
LEFT_JUSTIFY, 5, 2, pad).toString());
+    }
+
+    @Test
+    public void testEllipsis() {
+        assertEquals("foo", FormattableUtils.append("foo", new Formatter(), 0, 
-1, -1, "*").toString());
+        assertEquals("f*", FormattableUtils.append("foo", new Formatter(), 0, 
-1, 2, "*").toString());
+        assertEquals(" foo", FormattableUtils.append("foo", new Formatter(), 
0, 4, -1, "*").toString());
+        assertEquals("   foo", FormattableUtils.append("foo", new Formatter(), 
0, 6, -1, "*").toString());
+        assertEquals(" f*", FormattableUtils.append("foo", new Formatter(), 0, 
3, 2, "*").toString());
+        assertEquals("   f*", FormattableUtils.append("foo", new Formatter(), 
0, 5, 2, "*").toString());
+        assertEquals("foo ", FormattableUtils.append("foo", new Formatter(), 
LEFT_JUSTIFY, 4, -1, "*").toString());
+        assertEquals("foo   ", FormattableUtils.append("foo", new Formatter(), 
LEFT_JUSTIFY, 6, -1, "*").toString());
+        assertEquals("f* ", FormattableUtils.append("foo", new Formatter(), 
LEFT_JUSTIFY, 3, 2, "*").toString());
+        assertEquals("f*   ", FormattableUtils.append("foo", new Formatter(), 
LEFT_JUSTIFY, 5, 2, "*").toString());
+
+        assertEquals("foo", FormattableUtils.append("foo", new Formatter(), 0, 
-1, -1, "+*").toString());
+        assertEquals("+*", FormattableUtils.append("foo", new Formatter(), 0, 
-1, 2, "+*").toString());
+        assertEquals(" foo", FormattableUtils.append("foo", new Formatter(), 
0, 4, -1, "+*").toString());
+        assertEquals("   foo", FormattableUtils.append("foo", new Formatter(), 
0, 6, -1, "+*").toString());
+        assertEquals(" +*", FormattableUtils.append("foo", new Formatter(), 0, 
3, 2, "+*").toString());
+        assertEquals("   +*", FormattableUtils.append("foo", new Formatter(), 
0, 5, 2, "+*").toString());
+        assertEquals("foo ", FormattableUtils.append("foo", new Formatter(), 
LEFT_JUSTIFY, 4, -1, "+*").toString());
+        assertEquals("foo   ", FormattableUtils.append("foo", new Formatter(), 
LEFT_JUSTIFY, 6, -1, "+*").toString());
+        assertEquals("+* ", FormattableUtils.append("foo", new Formatter(), 
LEFT_JUSTIFY, 3, 2, "+*").toString());
+        assertEquals("+*   ", FormattableUtils.append("foo", new Formatter(), 
LEFT_JUSTIFY, 5, 2, "+*").toString());
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testIllegalEllipsis() {
+        FormattableUtils.append("foo", new Formatter(), 0, -1, 1, "xx");
+    }
+
+    @Test
+    public void testAlternatePadCharAndEllipsis() {
+        assertEquals("foo", FormattableUtils.append("foo", new Formatter(), 0, 
-1, -1, '_', "*").toString());
+        assertEquals("f*", FormattableUtils.append("foo", new Formatter(), 0, 
-1, 2, '_', "*").toString());
+        assertEquals("_foo", FormattableUtils.append("foo", new Formatter(), 
0, 4, -1, '_', "*").toString());
+        assertEquals("___foo", FormattableUtils.append("foo", new Formatter(), 
0, 6, -1, '_', "*").toString());
+        assertEquals("_f*", FormattableUtils.append("foo", new Formatter(), 0, 
3, 2, '_', "*").toString());
+        assertEquals("___f*", FormattableUtils.append("foo", new Formatter(), 
0, 5, 2, '_', "*").toString());
+        assertEquals("foo_", FormattableUtils.append("foo", new Formatter(), 
LEFT_JUSTIFY, 4, -1, '_', "*").toString());
+        assertEquals("foo___", FormattableUtils.append("foo", new Formatter(), 
LEFT_JUSTIFY, 6, -1, '_', "*").toString());
+        assertEquals("f*_", FormattableUtils.append("foo", new Formatter(), 
LEFT_JUSTIFY, 3, 2, '_', "*").toString());
+        assertEquals("f*___", FormattableUtils.append("foo", new Formatter(), 
LEFT_JUSTIFY, 5, 2, '_', "*").toString());
+
+        assertEquals("foo", FormattableUtils.append("foo", new Formatter(), 0, 
-1, -1, '_', "+*").toString());
+        assertEquals("+*", FormattableUtils.append("foo", new Formatter(), 0, 
-1, 2, '_', "+*").toString());
+        assertEquals("_foo", FormattableUtils.append("foo", new Formatter(), 
0, 4, -1, '_', "+*").toString());
+        assertEquals("___foo", FormattableUtils.append("foo", new Formatter(), 
0, 6, -1, '_', "+*").toString());
+        assertEquals("_+*", FormattableUtils.append("foo", new Formatter(), 0, 
3, 2, '_', "+*").toString());
+        assertEquals("___+*", FormattableUtils.append("foo", new Formatter(), 
0, 5, 2, '_', "+*").toString());
+        assertEquals("foo_", FormattableUtils.append("foo", new Formatter(), 
LEFT_JUSTIFY, 4, -1, '_', "+*").toString());
+        assertEquals("foo___", FormattableUtils.append("foo", new Formatter(), 
LEFT_JUSTIFY, 6, -1, '_', "+*").toString());
+        assertEquals("+*_", FormattableUtils.append("foo", new Formatter(), 
LEFT_JUSTIFY, 3, 2, '_', "+*").toString());
+        assertEquals("+*___", FormattableUtils.append("foo", new Formatter(), 
LEFT_JUSTIFY, 5, 2, '_', "+*").toString());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/6f24aa45/src/test/java/org/apache/commons/text/StrBuilderAppendInsertTest.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/commons/text/StrBuilderAppendInsertTest.java 
b/src/test/java/org/apache/commons/text/StrBuilderAppendInsertTest.java
new file mode 100644
index 0000000..228c8df
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/StrBuilderAppendInsertTest.java
@@ -0,0 +1,1607 @@
+/*
+ * 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.text.DecimalFormatSymbols;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+
+import org.apache.commons.lang3.SystemUtils;
+
+/**
+ * Unit tests for {@link StrBuilder}.
+ */
+public class StrBuilderAppendInsertTest {
+
+    /** The system line separator. */
+    private static final String SEP = SystemUtils.LINE_SEPARATOR;
+
+    /** Test subclass of Object, with a toString method. */
+    private static final Object FOO = new Object() {
+        @Override
+        public String toString() {
+            return "foo";
+        }
+    };
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendNewLine() {
+        StrBuilder sb = new StrBuilder("---");
+        sb.appendNewLine().append("+++");
+        assertEquals("---" + SEP + "+++", sb.toString());
+        
+        sb = new StrBuilder("---");
+        
sb.setNewLineText("#").appendNewLine().setNewLineText(null).appendNewLine();
+        assertEquals("---#" + SEP, sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendWithNullText() {
+        final StrBuilder sb = new StrBuilder();
+        sb.setNullText("NULL");
+        assertEquals("", sb.toString());
+
+        sb.appendNull();
+        assertEquals("NULL", sb.toString());
+
+        sb.append((Object) null);
+        assertEquals("NULLNULL", sb.toString());
+
+        sb.append(FOO);
+        assertEquals("NULLNULLfoo", sb.toString());
+
+        sb.append((String) null);
+        assertEquals("NULLNULLfooNULL", sb.toString());
+
+        sb.append("");
+        assertEquals("NULLNULLfooNULL", sb.toString());
+
+        sb.append("bar");
+        assertEquals("NULLNULLfooNULLbar", sb.toString());
+
+        sb.append((StringBuffer) null);
+        assertEquals("NULLNULLfooNULLbarNULL", sb.toString());
+
+        sb.append(new StringBuffer("baz"));
+        assertEquals("NULLNULLfooNULLbarNULLbaz", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppend_Object() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendNull();
+        assertEquals("", sb.toString());
+
+        sb.append((Object) null);
+        assertEquals("", sb.toString());
+
+        sb.append(FOO);
+        assertEquals("foo", sb.toString());
+
+        sb.append((StringBuffer) null);
+        assertEquals("foo", sb.toString());
+
+        sb.append(new StringBuffer("baz"));
+        assertEquals("foobaz", sb.toString());
+
+        sb.append(new StrBuilder("yes"));
+        assertEquals("foobazyes", sb.toString());
+
+        sb.append((CharSequence) "Seq");
+        assertEquals("foobazyesSeq", sb.toString());
+
+        sb.append(new StringBuilder("bld")); // Check it supports StringBuilder
+        assertEquals("foobazyesSeqbld", sb.toString());
+    }
+    
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppend_StringBuilder() {
+        StrBuilder sb = new StrBuilder();
+        sb.setNullText("NULL").append((String) null);
+        assertEquals("NULL", sb.toString());
+
+        sb = new StrBuilder();
+        sb.append(new StringBuilder("foo"));
+        assertEquals("foo", sb.toString());
+
+        sb.append(new StringBuilder(""));
+        assertEquals("foo", sb.toString());
+
+        sb.append(new StringBuilder("bar"));
+        assertEquals("foobar", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppend_String() {
+        StrBuilder sb = new StrBuilder();
+        sb.setNullText("NULL").append((String) null);
+        assertEquals("NULL", sb.toString());
+
+        sb = new StrBuilder();
+        sb.append("foo");
+        assertEquals("foo", sb.toString());
+
+        sb.append("");
+        assertEquals("foo", sb.toString());
+
+        sb.append("bar");
+        assertEquals("foobar", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppend_String_int_int() {
+        StrBuilder sb = new StrBuilder();
+        sb.setNullText("NULL").append((String) null, 0, 1);
+        assertEquals("NULL", sb.toString());
+
+        sb = new StrBuilder();
+        sb.append("foo", 0, 3);
+        assertEquals("foo", sb.toString());
+
+        try {
+            sb.append("bar", -1, 1);
+            fail("append(char[], -1,) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append("bar", 3, 1);
+            fail("append(char[], 3,) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append("bar", 1, -1);
+            fail("append(char[],, -1) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append("bar", 1, 3);
+            fail("append(char[], 1, 3) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append("bar", -1, 3);
+            fail("append(char[], -1, 3) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append("bar", 4, 0);
+            fail("append(char[], 4, 0) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.append("bar", 3, 0);
+        assertEquals("foo", sb.toString());
+
+        sb.append("abcbardef", 3, 3);
+        assertEquals("foobar", sb.toString());
+
+        sb.append( (CharSequence)"abcbardef", 4, 3);
+        assertEquals("foobarard", sb.toString());
+    }
+    
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppend_StringBuilder_int_int() {
+        StrBuilder sb = new StrBuilder();
+        sb.setNullText("NULL").append((String) null, 0, 1);
+        assertEquals("NULL", sb.toString());
+
+        sb = new StrBuilder();
+        sb.append(new StringBuilder("foo"), 0, 3);
+        assertEquals("foo", sb.toString());
+
+        try {
+            sb.append(new StringBuilder("bar"), -1, 1);
+            fail("append(StringBuilder, -1,) expected 
IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new StringBuilder("bar"), 3, 1);
+            fail("append(StringBuilder, 3,) expected 
IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new StringBuilder("bar"), 1, -1);
+            fail("append(StringBuilder,, -1) expected 
IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new StringBuilder("bar"), 1, 3);
+            fail("append(StringBuilder, 1, 3) expected 
IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new StringBuilder("bar"), -1, 3);
+            fail("append(StringBuilder, -1, 3) expected 
IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new StringBuilder("bar"), 4, 0);
+            fail("append(StringBuilder, 4, 0) expected 
IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.append(new StringBuilder("bar"), 3, 0);
+        assertEquals("foo", sb.toString());
+
+        sb.append(new StringBuilder("abcbardef"), 3, 3);
+        assertEquals("foobar", sb.toString());
+
+        sb.append( new StringBuilder("abcbardef"), 4, 3);
+        assertEquals("foobarard", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppend_StringBuffer() {
+        StrBuilder sb = new StrBuilder();
+        sb.setNullText("NULL").append((StringBuffer) null);
+        assertEquals("NULL", sb.toString());
+
+        sb = new StrBuilder();
+        sb.append(new StringBuffer("foo"));
+        assertEquals("foo", sb.toString());
+
+        sb.append(new StringBuffer(""));
+        assertEquals("foo", sb.toString());
+
+        sb.append(new StringBuffer("bar"));
+        assertEquals("foobar", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppend_StringBuffer_int_int() {
+        StrBuilder sb = new StrBuilder();
+        sb.setNullText("NULL").append((StringBuffer) null, 0, 1);
+        assertEquals("NULL", sb.toString());
+
+        sb = new StrBuilder();
+        sb.append(new StringBuffer("foo"), 0, 3);
+        assertEquals("foo", sb.toString());
+
+        try {
+            sb.append(new StringBuffer("bar"), -1, 1);
+            fail("append(char[], -1,) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new StringBuffer("bar"), 3, 1);
+            fail("append(char[], 3,) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new StringBuffer("bar"), 1, -1);
+            fail("append(char[],, -1) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new StringBuffer("bar"), 1, 3);
+            fail("append(char[], 1, 3) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new StringBuffer("bar"), -1, 3);
+            fail("append(char[], -1, 3) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new StringBuffer("bar"), 4, 0);
+            fail("append(char[], 4, 0) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.append(new StringBuffer("bar"), 3, 0);
+        assertEquals("foo", sb.toString());
+
+        sb.append(new StringBuffer("abcbardef"), 3, 3);
+        assertEquals("foobar", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppend_StrBuilder() {
+        StrBuilder sb = new StrBuilder();
+        sb.setNullText("NULL").append((StrBuilder) null);
+        assertEquals("NULL", sb.toString());
+
+        sb = new StrBuilder();
+        sb.append(new StrBuilder("foo"));
+        assertEquals("foo", sb.toString());
+
+        sb.append(new StrBuilder(""));
+        assertEquals("foo", sb.toString());
+
+        sb.append(new StrBuilder("bar"));
+        assertEquals("foobar", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppend_StrBuilder_int_int() {
+        StrBuilder sb = new StrBuilder();
+        sb.setNullText("NULL").append((StrBuilder) null, 0, 1);
+        assertEquals("NULL", sb.toString());
+
+        sb = new StrBuilder();
+        sb.append(new StrBuilder("foo"), 0, 3);
+        assertEquals("foo", sb.toString());
+
+        try {
+            sb.append(new StrBuilder("bar"), -1, 1);
+            fail("append(char[], -1,) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new StrBuilder("bar"), 3, 1);
+            fail("append(char[], 3,) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new StrBuilder("bar"), 1, -1);
+            fail("append(char[],, -1) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new StrBuilder("bar"), 1, 3);
+            fail("append(char[], 1, 3) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new StrBuilder("bar"), -1, 3);
+            fail("append(char[], -1, 3) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new StrBuilder("bar"), 4, 0);
+            fail("append(char[], 4, 0) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.append(new StrBuilder("bar"), 3, 0);
+        assertEquals("foo", sb.toString());
+
+        sb.append(new StrBuilder("abcbardef"), 3, 3);
+        assertEquals("foobar", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppend_CharArray() {
+        StrBuilder sb = new StrBuilder();
+        sb.setNullText("NULL").append((char[]) null);
+        assertEquals("NULL", sb.toString());
+
+        sb = new StrBuilder();
+        sb.append(new char[0]);
+        assertEquals("", sb.toString());
+
+        sb.append(new char[]{'f', 'o', 'o'});
+        assertEquals("foo", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppend_CharArray_int_int() {
+        StrBuilder sb = new StrBuilder();
+        sb.setNullText("NULL").append((char[]) null, 0, 1);
+        assertEquals("NULL", sb.toString());
+
+        sb = new StrBuilder();
+        sb.append(new char[]{'f', 'o', 'o'}, 0, 3);
+        assertEquals("foo", sb.toString());
+
+        try {
+            sb.append(new char[]{'b', 'a', 'r'}, -1, 1);
+            fail("append(char[], -1,) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new char[]{'b', 'a', 'r'}, 3, 1);
+            fail("append(char[], 3,) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new char[]{'b', 'a', 'r'}, 1, -1);
+            fail("append(char[],, -1) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new char[]{'b', 'a', 'r'}, 1, 3);
+            fail("append(char[], 1, 3) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new char[]{'b', 'a', 'r'}, -1, 3);
+            fail("append(char[], -1, 3) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        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);
+        assertEquals("foo", sb.toString());
+
+        sb.append(new char[]{'a', 'b', 'c', 'b', 'a', 'r', 'd', 'e', 'f'}, 3, 
3);
+        assertEquals("foobar", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppend_Boolean() {
+        final StrBuilder sb = new StrBuilder();
+        sb.append(true);
+        assertEquals("true", sb.toString());
+
+        sb.append(false);
+        assertEquals("truefalse", sb.toString());
+
+        sb.append('!');
+        assertEquals("truefalse!", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppend_PrimitiveNumber() {
+        final StrBuilder sb = new StrBuilder();
+        sb.append(0);
+        assertEquals("0", sb.toString());
+
+        sb.append(1L);
+        assertEquals("01", sb.toString());
+
+        sb.append(2.3f);
+        assertEquals("012.3", sb.toString());
+
+        sb.append(4.5d);
+        assertEquals("012.34.5", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    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) {
+                count[0]++;
+                return super.append(str);
+            }
+            @Override
+            public StrBuilder appendNewLine() {
+                count[1]++;
+                return super.appendNewLine();
+            }
+        };
+        sb.appendln("Hello %s", "Alice");
+        assertEquals("Hello Alice" + SEP, sb.toString());
+        assertEquals(2, count[0]);  // appendNewLine() calls append(String)
+        assertEquals(1, count[1]);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendln_Object() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendln((Object) null);
+        assertEquals("" + SEP, sb.toString());
+
+        sb.appendln(FOO);
+        assertEquals(SEP + "foo" + SEP, sb.toString());
+
+        sb.appendln(Integer.valueOf(6));
+        assertEquals(SEP + "foo" + SEP + "6" + SEP, sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    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 String str) {
+                count[0]++;
+                return super.append(str);
+            }
+            @Override
+            public StrBuilder appendNewLine() {
+                count[1]++;
+                return super.appendNewLine();
+            }
+        };
+        sb.appendln("foo");
+        assertEquals("foo" + SEP, sb.toString());
+        assertEquals(2, count[0]);  // appendNewLine() calls append(String)
+        assertEquals(1, count[1]);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    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 String str, final int startIndex, 
final int length) {
+                count[0]++;
+                return super.append(str, startIndex, length);
+            }
+            @Override
+            public StrBuilder appendNewLine() {
+                count[1]++;
+                return super.appendNewLine();
+            }
+        };
+        sb.appendln("foo", 0, 3);
+        assertEquals("foo" + SEP, sb.toString());
+        assertEquals(1, count[0]);
+        assertEquals(1, count[1]);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    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 StringBuffer str) {
+                count[0]++;
+                return super.append(str);
+            }
+            @Override
+            public StrBuilder appendNewLine() {
+                count[1]++;
+                return super.appendNewLine();
+            }
+        };
+        sb.appendln(new StringBuffer("foo"));
+        assertEquals("foo" + SEP, sb.toString());
+        assertEquals(1, count[0]);
+        assertEquals(1, count[1]);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    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 StringBuilder str) {
+                count[0]++;
+                return super.append(str);
+            }
+            @Override
+            public StrBuilder appendNewLine() {
+                count[1]++;
+                return super.appendNewLine();
+            }
+        };
+        sb.appendln(new StringBuilder("foo"));
+        assertEquals("foo" + SEP, sb.toString());
+        assertEquals(1, count[0]);
+        assertEquals(1, count[1]);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    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 StringBuffer str, final int 
startIndex, final int length) {
+                count[0]++;
+                return super.append(str, startIndex, length);
+            }
+            @Override
+            public StrBuilder appendNewLine() {
+                count[1]++;
+                return super.appendNewLine();
+            }
+        };
+        sb.appendln(new StringBuffer("foo"), 0, 3);
+        assertEquals("foo" + SEP, sb.toString());
+        assertEquals(1, count[0]);
+        assertEquals(1, count[1]);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    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 StringBuilder str, final int 
startIndex, final int length) {
+                count[0]++;
+                return super.append(str, startIndex, length);
+            }
+            @Override
+            public StrBuilder appendNewLine() {
+                count[1]++;
+                return super.appendNewLine();
+            }
+        };
+        sb.appendln(new StringBuilder("foo"), 0, 3);
+        assertEquals("foo" + SEP, sb.toString());
+        assertEquals(1, count[0]);
+        assertEquals(1, count[1]);
+    }
+
+    //-----------------------------------------------------------------------
+    @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 StrBuilder str) {
+                count[0]++;
+                return super.append(str);
+            }
+            @Override
+            public StrBuilder appendNewLine() {
+                count[1]++;
+                return super.appendNewLine();
+            }
+        };
+        sb.appendln(new StrBuilder("foo"));
+        assertEquals("foo" + SEP, sb.toString());
+        assertEquals(1, count[0]);
+        assertEquals(1, count[1]);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    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 StrBuilder str, final int 
startIndex, final int length) {
+                count[0]++;
+                return super.append(str, startIndex, length);
+            }
+            @Override
+            public StrBuilder appendNewLine() {
+                count[1]++;
+                return super.appendNewLine();
+            }
+        };
+        sb.appendln(new StrBuilder("foo"), 0, 3);
+        assertEquals("foo" + SEP, sb.toString());
+        assertEquals(1, count[0]);
+        assertEquals(1, count[1]);
+    }
+
+    //-----------------------------------------------------------------------
+    @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 char[] str) {
+                count[0]++;
+                return super.append(str);
+            }
+            @Override
+            public StrBuilder appendNewLine() {
+                count[1]++;
+                return super.appendNewLine();
+            }
+        };
+        sb.appendln("foo".toCharArray());
+        assertEquals("foo" + SEP, sb.toString());
+        assertEquals(1, count[0]);
+        assertEquals(1, count[1]);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    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 char[] str, final int startIndex, 
final int length) {
+                count[0]++;
+                return super.append(str, startIndex, length);
+            }
+            @Override
+            public StrBuilder appendNewLine() {
+                count[1]++;
+                return super.appendNewLine();
+            }
+        };
+        sb.appendln("foo".toCharArray(), 0, 3);
+        assertEquals("foo" + SEP, sb.toString());
+        assertEquals(1, count[0]);
+        assertEquals(1, count[1]);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendln_Boolean() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendln(true);
+        assertEquals("true" + SEP, sb.toString());
+        
+        sb.clear();
+        sb.appendln(false);
+        assertEquals("false" + SEP, sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendln_PrimitiveNumber() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendln(0);
+        assertEquals("0" + SEP, sb.toString());
+        
+        sb.clear();
+        sb.appendln(1L);
+        assertEquals("1" + SEP, sb.toString());
+        
+        sb.clear();
+        sb.appendln(2.3f);
+        assertEquals("2.3" + SEP, sb.toString());
+        
+        sb.clear();
+        sb.appendln(4.5d);
+        assertEquals("4.5" + SEP, sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendPadding() {
+        final StrBuilder sb = new StrBuilder();
+        sb.append("foo");
+        assertEquals("foo", sb.toString());
+
+        sb.appendPadding(-1, '-');
+        assertEquals("foo", sb.toString());
+
+        sb.appendPadding(0, '-');
+        assertEquals("foo", sb.toString());
+
+        sb.appendPadding(1, '-');
+        assertEquals("foo-", sb.toString());
+
+        sb.appendPadding(16, '-');
+        assertEquals(20, sb.length());
+        //            12345678901234567890
+        assertEquals("foo-----------------", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendFixedWidthPadLeft() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendFixedWidthPadLeft("foo", -1, '-');
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadLeft("foo", 0, '-');
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadLeft("foo", 1, '-');
+        assertEquals("o", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadLeft("foo", 2, '-');
+        assertEquals("oo", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadLeft("foo", 3, '-');
+        assertEquals("foo", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadLeft("foo", 4, '-');
+        assertEquals("-foo", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadLeft("foo", 10, '-');
+        assertEquals(10, sb.length());
+        //            1234567890
+        assertEquals("-------foo", sb.toString());
+
+        sb.clear();
+        sb.setNullText("null");
+        sb.appendFixedWidthPadLeft(null, 5, '-');
+        assertEquals("-null", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendFixedWidthPadLeft_int() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendFixedWidthPadLeft(123, -1, '-');
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadLeft(123, 0, '-');
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadLeft(123, 1, '-');
+        assertEquals("3", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadLeft(123, 2, '-');
+        assertEquals("23", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadLeft(123, 3, '-');
+        assertEquals("123", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadLeft(123, 4, '-');
+        assertEquals("-123", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadLeft(123, 10, '-');
+        assertEquals(10, sb.length());
+        //            1234567890
+        assertEquals("-------123", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendFixedWidthPadRight() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendFixedWidthPadRight("foo", -1, '-');
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadRight("foo", 0, '-');
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadRight("foo", 1, '-');
+        assertEquals("f", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadRight("foo", 2, '-');
+        assertEquals("fo", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadRight("foo", 3, '-');
+        assertEquals("foo", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadRight("foo", 4, '-');
+        assertEquals("foo-", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadRight("foo", 10, '-');
+        assertEquals(10, sb.length());
+        //            1234567890
+        assertEquals("foo-------", sb.toString());
+
+        sb.clear();
+        sb.setNullText("null");
+        sb.appendFixedWidthPadRight(null, 5, '-');
+        assertEquals("null-", sb.toString());
+    }
+
+    // See: http://issues.apache.org/jira/browse/LANG-299
+    @Test
+    public void testLang299() {
+        final StrBuilder sb = new StrBuilder(1);
+        sb.appendFixedWidthPadRight("foo", 1, '-');
+        assertEquals("f", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendFixedWidthPadRight_int() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendFixedWidthPadRight(123, -1, '-');
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadRight(123, 0, '-');
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadRight(123, 1, '-');
+        assertEquals("1", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadRight(123, 2, '-');
+        assertEquals("12", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadRight(123, 3, '-');
+        assertEquals("123", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadRight(123, 4, '-');
+        assertEquals("123-", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadRight(123, 10, '-');
+        assertEquals(10, sb.length());
+        //            1234567890
+        assertEquals("123-------", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppend_FormattedString() {
+        StrBuilder sb;
+
+        sb = new StrBuilder();
+        sb.append("Hi", (Object[]) null);
+        assertEquals("Hi", sb.toString());
+
+        sb = new StrBuilder();
+        sb.append("Hi", "Alice");
+        assertEquals("Hi", sb.toString());
+
+        sb = new StrBuilder();
+        sb.append("Hi %s", "Alice");
+        assertEquals("Hi Alice", sb.toString());
+
+        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";
+        assertEquals(expected, sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendAll_Array() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendAll((Object[]) null);
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendAll(new Object[0]);
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendAll(new Object[]{"foo", "bar", "baz"});
+        assertEquals("foobarbaz", sb.toString());
+
+        sb.clear();
+        sb.appendAll("foo", "bar", "baz");
+        assertEquals("foobarbaz", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendAll_Collection() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendAll((Collection<?>) null);
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendAll(Collections.EMPTY_LIST);
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendAll(Arrays.asList(new Object[]{"foo", "bar", "baz"}));
+        assertEquals("foobarbaz", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendAll_Iterator() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendAll((Iterator<?>) null);
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendAll(Collections.EMPTY_LIST.iterator());
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendAll(Arrays.asList(new Object[]{"foo", "bar", 
"baz"}).iterator());
+        assertEquals("foobarbaz", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendWithSeparators_Array() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendWithSeparators((Object[]) null, ",");
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendWithSeparators(new Object[0], ",");
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendWithSeparators(new Object[]{"foo", "bar", "baz"}, ",");
+        assertEquals("foo,bar,baz", sb.toString());
+
+        sb.clear();
+        sb.appendWithSeparators(new Object[]{"foo", "bar", "baz"}, null);
+        assertEquals("foobarbaz", sb.toString());
+
+        sb.clear();
+        sb.appendWithSeparators(new Object[]{"foo", null, "baz"}, ",");
+        assertEquals("foo,,baz", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendWithSeparators_Collection() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendWithSeparators((Collection<?>) null, ",");
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendWithSeparators(Collections.EMPTY_LIST, ",");
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendWithSeparators(Arrays.asList(new Object[]{"foo", "bar", 
"baz"}), ",");
+        assertEquals("foo,bar,baz", sb.toString());
+
+        sb.clear();
+        sb.appendWithSeparators(Arrays.asList(new Object[]{"foo", "bar", 
"baz"}), null);
+        assertEquals("foobarbaz", sb.toString());
+
+        sb.clear();
+        sb.appendWithSeparators(Arrays.asList(new Object[]{"foo", null, 
"baz"}), ",");
+        assertEquals("foo,,baz", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendWithSeparators_Iterator() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendWithSeparators((Iterator<?>) null, ",");
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendWithSeparators(Collections.EMPTY_LIST.iterator(), ",");
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendWithSeparators(Arrays.asList(new Object[]{"foo", "bar", 
"baz"}).iterator(), ",");
+        assertEquals("foo,bar,baz", sb.toString());
+
+        sb.clear();
+        sb.appendWithSeparators(Arrays.asList(new Object[]{"foo", "bar", 
"baz"}).iterator(), null);
+        assertEquals("foobarbaz", sb.toString());
+
+        sb.clear();
+        sb.appendWithSeparators(Arrays.asList(new Object[]{"foo", null, 
"baz"}).iterator(), ",");
+        assertEquals("foo,,baz", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendWithSeparatorsWithNullText() {
+        final StrBuilder sb = new StrBuilder();
+        sb.setNullText("null");
+        sb.appendWithSeparators(new Object[]{"foo", null, "baz"}, ",");
+        assertEquals("foo,null,baz", sb.toString());
+
+        sb.clear();
+        sb.appendWithSeparators(Arrays.asList(new Object[]{"foo", null, 
"baz"}), ",");
+        assertEquals("foo,null,baz", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendSeparator_String() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendSeparator(",");  // no effect
+        assertEquals("", sb.toString());
+        sb.append("foo");
+        assertEquals("foo", sb.toString());
+        sb.appendSeparator(",");
+        assertEquals("foo,", sb.toString());
+    }
+    
+    //-----------------------------------------------------------------------
+    @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);
+        assertEquals("", sb.toString());
+        sb.appendSeparator(standardSeparator, null);
+        assertEquals("", sb.toString());
+        sb.appendSeparator(standardSeparator, startSeparator); 
+        assertEquals(startSeparator, sb.toString());
+        sb.appendSeparator(null, null); 
+        assertEquals(startSeparator, sb.toString());
+        sb.appendSeparator(null, startSeparator); 
+        assertEquals(startSeparator, sb.toString());
+        sb.append(foo);
+        assertEquals(startSeparator + foo, sb.toString());
+        sb.appendSeparator(standardSeparator, startSeparator);
+        assertEquals(startSeparator + foo + standardSeparator, sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendSeparator_char() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendSeparator(',');  // no effect
+        assertEquals("", sb.toString());
+        sb.append("foo");
+        assertEquals("foo", sb.toString());
+        sb.appendSeparator(',');
+        assertEquals("foo,", sb.toString());
+    }
+    @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
+        assertEquals(String.valueOf(startSeparator), sb.toString());
+        sb.append(foo);
+        assertEquals(String.valueOf(startSeparator) + foo, sb.toString());
+        sb.appendSeparator(standardSeparator, startSeparator);
+        assertEquals(String.valueOf(startSeparator) + foo + standardSeparator, 
sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendSeparator_String_int() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendSeparator(",", 0);  // no effect
+        assertEquals("", sb.toString());
+        sb.append("foo");
+        assertEquals("foo", sb.toString());
+        sb.appendSeparator(",", 1);
+        assertEquals("foo,", sb.toString());
+        
+        sb.appendSeparator(",", -1);  // no effect
+        assertEquals("foo,", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendSeparator_char_int() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendSeparator(',', 0);  // no effect
+        assertEquals("", sb.toString());
+        sb.append("foo");
+        assertEquals("foo", sb.toString());
+        sb.appendSeparator(',', 1);
+        assertEquals("foo,", sb.toString());
+        
+        sb.appendSeparator(',', -1);  // no effect
+        assertEquals("foo,", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testInsert() {
+
+        final StrBuilder sb = new StrBuilder();
+        sb.append("barbaz");
+        assertEquals("barbaz", sb.toString());
+
+        try {
+            sb.insert(-1, FOO);
+            fail("insert(-1, Object) expected 
StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.insert(7, FOO);
+            fail("insert(7, Object) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.insert(0, (Object) null);
+        assertEquals("barbaz", sb.toString());
+
+        sb.insert(0, FOO);
+        assertEquals("foobarbaz", sb.toString());
+
+        sb.clear();
+        sb.append("barbaz");
+        assertEquals("barbaz", sb.toString());
+
+        try {
+            sb.insert(-1, "foo");
+            fail("insert(-1, String) expected 
StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.insert(7, "foo");
+            fail("insert(7, String) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.insert(0, (String) null);
+        assertEquals("barbaz", sb.toString());
+
+        sb.insert(0, "foo");
+        assertEquals("foobarbaz", sb.toString());
+
+        sb.clear();
+        sb.append("barbaz");
+        assertEquals("barbaz", sb.toString());
+
+        try {
+            sb.insert(-1, new char[]{'f', 'o', 'o'});
+            fail("insert(-1, char[]) expected 
StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.insert(7, new char[]{'f', 'o', 'o'});
+            fail("insert(7, char[]) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.insert(0, (char[]) null);
+        assertEquals("barbaz", sb.toString());
+
+        sb.insert(0, new char[0]);
+        assertEquals("barbaz", sb.toString());
+
+        sb.insert(0, new char[]{'f', 'o', 'o'});
+        assertEquals("foobarbaz", sb.toString());
+
+        sb.clear();
+        sb.append("barbaz");
+        assertEquals("barbaz", sb.toString());
+
+        try {
+            sb.insert(-1, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 
'f'}, 3, 3);
+            fail("insert(-1, char[], 3, 3) expected 
StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.insert(7, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 
'f'}, 3, 3);
+            fail("insert(7, char[], 3, 3) expected 
StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.insert(0, (char[]) null, 0, 0);
+        assertEquals("barbaz", sb.toString());
+
+        sb.insert(0, new char[0], 0, 0);
+        assertEquals("barbaz", sb.toString());
+
+        try {
+            sb.insert(0, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 
'f'}, -1, 3);
+            fail("insert(0, char[], -1, 3) expected 
StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.insert(0, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 
'f'}, 10, 3);
+            fail("insert(0, char[], 10, 3) expected 
StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.insert(0, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 
'f'}, 0, -1);
+            fail("insert(0, char[], 0, -1) expected 
StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.insert(0, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 
'f'}, 0, 10);
+            fail("insert(0, char[], 0, 10) expected 
StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.insert(0, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, 
0, 0);
+        assertEquals("barbaz", sb.toString());
+
+        sb.insert(0, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, 
3, 3);
+        assertEquals("foobarbaz", sb.toString());
+
+        sb.clear();
+        sb.append("barbaz");
+        assertEquals("barbaz", sb.toString());
+
+        try {
+            sb.insert(-1, true);
+            fail("insert(-1, boolean) expected 
StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.insert(7, true);
+            fail("insert(7, boolean) expected 
StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.insert(0, true);
+        assertEquals("truebarbaz", sb.toString());
+
+        sb.insert(0, false);
+        assertEquals("falsetruebarbaz", sb.toString());
+
+        sb.clear();
+        sb.append("barbaz");
+        assertEquals("barbaz", sb.toString());
+
+        try {
+            sb.insert(-1, '!');
+            fail("insert(-1, char) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.insert(7, '!');
+            fail("insert(7, char) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.insert(0, '!');
+        assertEquals("!barbaz", sb.toString());
+
+        sb.clear();
+        sb.append("barbaz");
+        assertEquals("barbaz", sb.toString());
+
+        try {
+            sb.insert(-1, 0);
+            fail("insert(-1, int) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.insert(7, 0);
+            fail("insert(7, int) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.insert(0, '0');
+        assertEquals("0barbaz", sb.toString());
+
+        sb.clear();
+        sb.append("barbaz");
+        assertEquals("barbaz", sb.toString());
+
+        try {
+            sb.insert(-1, 1L);
+            fail("insert(-1, long) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.insert(7, 1L);
+            fail("insert(7, long) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.insert(0, 1L);
+        assertEquals("1barbaz", sb.toString());
+
+        sb.clear();
+        sb.append("barbaz");
+        assertEquals("barbaz", sb.toString());
+
+        try {
+            sb.insert(-1, 2.3F);
+            fail("insert(-1, float) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.insert(7, 2.3F);
+            fail("insert(7, float) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.insert(0, 2.3F);
+        assertEquals("2.3barbaz", sb.toString());
+
+        sb.clear();
+        sb.append("barbaz");
+        assertEquals("barbaz", sb.toString());
+
+        try {
+            sb.insert(-1, 4.5D);
+            fail("insert(-1, double) expected 
StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.insert(7, 4.5D);
+            fail("insert(7, double) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.insert(0, 4.5D);
+        assertEquals("4.5barbaz", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testInsertWithNullText() {
+        final StrBuilder sb = new StrBuilder();
+        sb.setNullText("null");
+        sb.append("barbaz");
+        assertEquals("barbaz", sb.toString());
+
+        try {
+            sb.insert(-1, FOO);
+            fail("insert(-1, Object) expected 
StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.insert(7, FOO);
+            fail("insert(7, Object) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.insert(0, (Object) null);
+        assertEquals("nullbarbaz", sb.toString());
+
+        sb.insert(0, FOO);
+        assertEquals("foonullbarbaz", sb.toString());
+
+        sb.clear();
+        sb.append("barbaz");
+        assertEquals("barbaz", sb.toString());
+
+        try {
+            sb.insert(-1, "foo");
+            fail("insert(-1, String) expected 
StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.insert(7, "foo");
+            fail("insert(7, String) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.insert(0, (String) null);
+        assertEquals("nullbarbaz", sb.toString());
+
+        sb.insert(0, "foo");
+        assertEquals("foonullbarbaz", sb.toString());
+
+        sb.insert(0, (char[]) null);
+        assertEquals("nullfoonullbarbaz", sb.toString());
+
+        sb.insert(0, (char[]) null, 0, 0);
+        assertEquals("nullnullfoonullbarbaz", sb.toString());
+    }
+}

Reply via email to