View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.text;
19  
20  import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
21  import static org.junit.jupiter.api.Assertions.assertArrayEquals;
22  import static org.junit.jupiter.api.Assertions.assertEquals;
23  import static org.junit.jupiter.api.Assertions.assertFalse;
24  import static org.junit.jupiter.api.Assertions.assertNotEquals;
25  import static org.junit.jupiter.api.Assertions.assertNotNull;
26  import static org.junit.jupiter.api.Assertions.assertNotSame;
27  import static org.junit.jupiter.api.Assertions.assertNull;
28  import static org.junit.jupiter.api.Assertions.assertSame;
29  import static org.junit.jupiter.api.Assertions.assertThrows;
30  import static org.junit.jupiter.api.Assertions.assertTrue;
31  
32  import java.io.IOException;
33  import java.io.Reader;
34  import java.io.StringReader;
35  import java.io.StringWriter;
36  import java.io.Writer;
37  import java.nio.ByteBuffer;
38  import java.nio.CharBuffer;
39  import java.nio.charset.Charset;
40  import java.util.Arrays;
41  import java.util.Locale;
42  
43  import org.apache.commons.io.output.NullAppendable;
44  import org.apache.commons.lang3.ArrayUtils;
45  import org.apache.commons.lang3.StringUtils;
46  import org.apache.commons.text.matcher.StringMatcher;
47  import org.apache.commons.text.matcher.StringMatcherFactory;
48  import org.junit.jupiter.api.Assumptions;
49  import org.junit.jupiter.api.Test;
50  
51  /**
52   * Tests {@link TextStringBuilder}.
53   */
54  public class TextStringBuilderTest {
55  
56      private static final class MockReadable implements Readable {
57  
58          private final CharBuffer src;
59  
60          MockReadable(final String src) {
61              this.src = CharBuffer.wrap(src);
62          }
63  
64          @Override
65          public int read(final CharBuffer cb) throws IOException {
66              return src.read(cb);
67          }
68      }
69  
70      static final StringMatcher A_NUMBER_MATCHER = (buffer, start, bufferStart, bufferEnd) -> {
71          if (buffer[start] == 'A') {
72              start++;
73              if (start < bufferEnd && buffer[start] >= '0' && buffer[start] <= '9') {
74                  return 2;
75              }
76          }
77          return 0;
78      };
79  
80      /**
81       * Clear the string builder and fill up to the specified length.
82       *
83       * @param sb the string builder
84       * @param length the length
85       */
86      private static void fill(final TextStringBuilder sb, final int length) {
87          sb.clear();
88          // Some initial data.
89          final int limit = Math.min(64, length);
90          for (int i = 0; i < limit; i++) {
91              sb.append(' ');
92          }
93          // Fill by doubling
94          while (sb.length() * 2L <= length) {
95              sb.append(sb);
96          }
97          // Remaining fill
98          sb.append(sb, 0, length - sb.length());
99          assertEquals(length, sb.length(), "Expected the buffer to be full to the given length");
100     }
101 
102     @Test
103     public void test_LANG_1131_EqualsWithNullTextStringBuilder() throws Exception {
104         final TextStringBuilder sb = new TextStringBuilder();
105         final TextStringBuilder other = null;
106         assertFalse(sb.equals(other));
107     }
108 
109     @Test
110     public void testAppendCharBuffer() {
111         final TextStringBuilder sb1 = new TextStringBuilder();
112         final CharBuffer buf = CharBuffer.allocate(10);
113         buf.append("0123456789");
114         buf.flip();
115         sb1.append(buf);
116         assertEquals("0123456789", sb1.toString());
117 
118         final TextStringBuilder sb2 = new TextStringBuilder();
119         sb2.append(buf, 1, 8);
120         assertEquals("12345678", sb2.toString());
121     }
122 
123     @Test
124     public void testAppendCharBufferException() throws Exception {
125         final TextStringBuilder sb = new TextStringBuilder("1234567890");
126         final String text = "Test";
127         final CharBuffer buffer = CharBuffer.allocate(sb.size() + text.length());
128         buffer.put(text);
129         buffer.flip();
130         try {
131             sb.append(buffer, -1, 12);
132         } catch (final StringIndexOutOfBoundsException e) {
133             assertEquals("startIndex must be valid", e.getMessage());
134         }
135 
136         try {
137             sb.append(buffer, 0, -1);
138         } catch (final StringIndexOutOfBoundsException e) {
139             assertEquals("length must be valid", e.getMessage());
140         }
141 
142         sb.append(buffer);
143         assertEquals("1234567890Test", sb.toString());
144     }
145 
146     @Test
147     public void testAppendCharBufferNull() throws Exception {
148         final TextStringBuilder sb = new TextStringBuilder("1234567890");
149         final CharBuffer buffer = null;
150         sb.append(buffer);
151         assertEquals("1234567890", sb.toString());
152 
153         final TextStringBuilder sb1 = new TextStringBuilder("1234567890");
154         final CharBuffer buffer1 = null;
155         sb.append(buffer1, 0, 0);
156         assertEquals("1234567890", sb1.toString());
157     }
158 
159     @Test
160     public void testAppendCharSequence() {
161         final CharSequence obj0 = null;
162         final CharSequence obj1 = new TextStringBuilder("test1");
163         final CharSequence obj2 = new StringBuilder("test2");
164         final CharSequence obj3 = new StringBuffer("test3");
165         final CharBuffer obj4 = CharBuffer.wrap("test4".toCharArray());
166 
167         final TextStringBuilder sb0 = new TextStringBuilder();
168         assertEquals("", sb0.append(obj0).toString());
169 
170         final TextStringBuilder sb1 = new TextStringBuilder();
171         assertEquals("test1", sb1.append(obj1).toString());
172 
173         final TextStringBuilder sb2 = new TextStringBuilder();
174         assertEquals("test2", sb2.append(obj2).toString());
175 
176         final TextStringBuilder sb3 = new TextStringBuilder();
177         assertEquals("test3", sb3.append(obj3).toString());
178 
179         final TextStringBuilder sb4 = new TextStringBuilder();
180         assertEquals("test4", sb4.append(obj4).toString());
181 
182         final TextStringBuilder sb5 = new TextStringBuilder();
183         assertEquals("", sb5.append(obj0, 0, 0).toString());
184     }
185 
186     @Test
187     public void testAppendln() {
188         final TextStringBuilder sb1 = new TextStringBuilder();
189         final char ch = 'c';
190         assertEquals("c" + System.lineSeparator(), sb1.appendln(ch).toString());
191     }
192 
193     @Test
194     public void testAppendStringBuilderNull() {
195         final TextStringBuilder sb1 = new TextStringBuilder();
196         final StringBuilder b = null;
197         assertEquals("", sb1.append(b).toString());
198 
199         final TextStringBuilder sb2 = new TextStringBuilder();
200         assertEquals("", sb2.append(b, 0, 0).toString());
201     }
202 
203     @Test
204     public void testAppendTakingTwoIntsWithIndexOutOfBoundsThrowsStringIndexOutOfBoundsExceptionTwo() {
205         assertThatExceptionOfType(StringIndexOutOfBoundsException.class).isThrownBy(() -> {
206             final Charset charset = Charset.defaultCharset();
207             final ByteBuffer byteBuffer = charset.encode("asdf");
208             final CharBuffer charBuffer = charset.decode(byteBuffer);
209 
210             new TextStringBuilder().append(charBuffer, 933, 654);
211         });
212     }
213 
214     @Test
215     public void testAppendTakingTwoIntsWithZeroThrowsStringIndexOutOfBoundsException() {
216         assertThatExceptionOfType(StringIndexOutOfBoundsException.class).isThrownBy(() -> {
217             final Charset charset = Charset.defaultCharset();
218             final ByteBuffer byteBuffer = charset.encode("end < start");
219             final CharBuffer charBuffer = charset.decode(byteBuffer);
220 
221             new TextStringBuilder(630).append(charBuffer, 0, 630);
222         });
223     }
224 
225     @Test
226     public void testAppendToAppendable() throws Exception {
227         final TextStringBuilder sb = new TextStringBuilder("1234567890");
228         final StringWriter writer = new StringWriter();
229         writer.append("Test");
230         sb.appendTo(NullAppendable.INSTANCE);
231         assertEquals("Test", writer.toString());
232     }
233 
234     @Test
235     public void testAppendToCharBuffer() throws Exception {
236         final TextStringBuilder sb = new TextStringBuilder("1234567890");
237         final String text = "Test ";
238         final CharBuffer buffer = CharBuffer.allocate(sb.size() + text.length());
239         buffer.put(text);
240 
241         sb.appendTo(buffer);
242 
243         buffer.flip();
244         assertEquals("Test 1234567890", buffer.toString());
245     }
246 
247     @Test
248     public void testAppendToStringBuffer() throws Exception {
249         final TextStringBuilder sb = new TextStringBuilder("1234567890");
250         final StringBuilder buffer = new StringBuilder("Test ");
251 
252         sb.appendTo(buffer);
253 
254         assertEquals("Test 1234567890", buffer.toString());
255     }
256 
257     @Test
258     public void testAppendToStringBuilder() throws Exception {
259         final TextStringBuilder sb = new TextStringBuilder("1234567890");
260         final StringBuilder builder = new StringBuilder("Test ");
261 
262         sb.appendTo(builder);
263 
264         assertEquals("Test 1234567890", builder.toString());
265     }
266 
267     @Test
268     public void testAppendToWriter() throws Exception {
269         final TextStringBuilder sb = new TextStringBuilder("1234567890");
270         final StringWriter writer = new StringWriter();
271         writer.append("Test ");
272 
273         sb.appendTo(writer);
274 
275         assertEquals("Test 1234567890", writer.toString());
276     }
277 
278     @Test
279     public void testAsBuilder() {
280         final TextStringBuilder sb = new TextStringBuilder().appendAll("Lorem", " ", "ipsum", " ", "dolor");
281         assertEquals(sb.toString(), sb.build());
282     }
283 
284     @Test
285     public void testAsReader() throws Exception {
286         final TextStringBuilder sb = new TextStringBuilder("some text");
287         try (Reader reader = sb.asReader()) {
288             assertTrue(reader.ready());
289             final char[] buf = new char[40];
290             assertEquals(9, reader.read(buf));
291             assertEquals("some text", new String(buf, 0, 9));
292 
293             assertEquals(-1, reader.read());
294             assertFalse(reader.ready());
295             assertEquals(0, reader.skip(2));
296             assertEquals(0, reader.skip(-1));
297 
298             assertTrue(reader.markSupported());
299         }
300         try (Reader reader = sb.asReader()) {
301             assertEquals('s', reader.read());
302             reader.mark(-1);
303             final char[] array = new char[3];
304             assertEquals(3, reader.read(array, 0, 3));
305             assertEquals('o', array[0]);
306             assertEquals('m', array[1]);
307             assertEquals('e', array[2]);
308             reader.reset();
309             assertEquals(1, reader.read(array, 1, 1));
310             assertEquals('o', array[0]);
311             assertEquals('o', array[1]);
312             assertEquals('e', array[2]);
313             assertEquals(2, reader.skip(2));
314             assertEquals(' ', reader.read());
315 
316             assertTrue(reader.ready());
317             reader.close();
318             assertTrue(reader.ready());
319         }
320         try (Reader reader = sb.asReader()) {
321             final char[] array = new char[3];
322             assertThrows(IndexOutOfBoundsException.class, () -> reader.read(array, -1, 0));
323             assertThrows(IndexOutOfBoundsException.class, () -> reader.read(array, 0, -1));
324             assertThrows(IndexOutOfBoundsException.class, () -> reader.read(array, 100, 1));
325             assertThrows(IndexOutOfBoundsException.class, () -> reader.read(array, 0, 100));
326             assertThrows(IndexOutOfBoundsException.class,
327                 () -> reader.read(array, Integer.MAX_VALUE, Integer.MAX_VALUE));
328 
329             assertEquals(0, reader.read(array, 0, 0));
330             assertEquals(0, array[0]);
331             assertEquals(0, array[1]);
332             assertEquals(0, array[2]);
333 
334             reader.skip(9);
335             assertEquals(-1, reader.read(array, 0, 1));
336 
337             reader.reset();
338             final char[] array2 = new char[30];
339             assertEquals(9, reader.read(array2, 0, 30));
340         }
341     }
342 
343     @Test
344     public void testAsSupplier() {
345         final TextStringBuilder sb = new TextStringBuilder().appendAll("Lorem", " ", "ipsum", " ", "dolor");
346         assertEquals(sb.toString(), sb.get());
347     }
348 
349     @Test
350     public void testAsTokenizer() throws Exception {
351         // from Javadoc
352         final TextStringBuilder b = new TextStringBuilder();
353         b.append("a b ");
354         final StringTokenizer t = b.asTokenizer();
355 
356         final String[] tokens1 = t.getTokenArray();
357         assertEquals(2, tokens1.length);
358         assertEquals("a", tokens1[0]);
359         assertEquals("b", tokens1[1]);
360         assertEquals(2, t.size());
361 
362         b.append("c d ");
363         final String[] tokens2 = t.getTokenArray();
364         assertEquals(2, tokens2.length);
365         assertEquals("a", tokens2[0]);
366         assertEquals("b", tokens2[1]);
367         assertEquals(2, t.size());
368         assertEquals("a", t.next());
369         assertEquals("b", t.next());
370 
371         t.reset();
372         final String[] tokens3 = t.getTokenArray();
373         assertEquals(4, tokens3.length);
374         assertEquals("a", tokens3[0]);
375         assertEquals("b", tokens3[1]);
376         assertEquals("c", tokens3[2]);
377         assertEquals("d", tokens3[3]);
378         assertEquals(4, t.size());
379         assertEquals("a", t.next());
380         assertEquals("b", t.next());
381         assertEquals("c", t.next());
382         assertEquals("d", t.next());
383 
384         assertEquals("a b c d ", t.getContent());
385     }
386 
387     @Test
388     public void testAsWriter() throws Exception {
389         final TextStringBuilder sb = new TextStringBuilder("base");
390         try (Writer writer = sb.asWriter()) {
391 
392             writer.write('l');
393             assertEquals("basel", sb.toString());
394 
395             writer.write(new char[] {'i', 'n'});
396             assertEquals("baselin", sb.toString());
397 
398             writer.write(new char[] {'n', 'e', 'r'}, 1, 2);
399             assertEquals("baseliner", sb.toString());
400 
401             writer.write(" rout");
402             assertEquals("baseliner rout", sb.toString());
403 
404             writer.write("ping that server", 1, 3);
405             assertEquals("baseliner routing", sb.toString());
406 
407             writer.flush(); // no effect
408             assertEquals("baseliner routing", sb.toString());
409 
410             writer.close(); // no effect
411             assertEquals("baseliner routing", sb.toString());
412 
413             writer.write(" hi"); // works after close
414             assertEquals("baseliner routing hi", sb.toString());
415 
416             sb.setLength(4); // mix and match
417             writer.write('d');
418             assertEquals("based", sb.toString());
419         }
420     }
421 
422     @Test
423     public void testCapacity() {
424         final TextStringBuilder sb = new TextStringBuilder();
425         assertEquals(sb.getBuffer().length, sb.capacity());
426 
427         sb.append("HelloWorldHelloWorldHelloWorldHelloWorld");
428         assertEquals(sb.getBuffer().length, sb.capacity());
429     }
430 
431     @Test
432     public void testCapacityAndLength() {
433         final TextStringBuilder sb = new TextStringBuilder();
434         assertEquals(32, sb.capacity());
435         assertEquals(0, sb.length());
436         assertEquals(0, sb.size());
437         assertTrue(sb.isEmpty());
438 
439         sb.minimizeCapacity();
440         assertEquals(0, sb.capacity());
441         assertEquals(0, sb.length());
442         assertEquals(0, sb.size());
443         assertTrue(sb.isEmpty());
444 
445         sb.ensureCapacity(32);
446         assertTrue(sb.capacity() >= 32);
447         assertEquals(0, sb.length());
448         assertEquals(0, sb.size());
449         assertTrue(sb.isEmpty());
450 
451         sb.append("foo");
452         assertTrue(sb.capacity() >= 32);
453         assertEquals(3, sb.length());
454         assertEquals(3, sb.size());
455         assertFalse(sb.isEmpty());
456 
457         sb.clear();
458         assertTrue(sb.capacity() >= 32);
459         assertEquals(0, sb.length());
460         assertEquals(0, sb.size());
461         assertTrue(sb.isEmpty());
462 
463         sb.append("123456789012345678901234567890123");
464         assertTrue(sb.capacity() > 32);
465         assertEquals(33, sb.length());
466         assertEquals(33, sb.size());
467         assertFalse(sb.isEmpty());
468 
469         sb.ensureCapacity(16);
470         assertTrue(sb.capacity() > 16);
471         assertEquals(33, sb.length());
472         assertEquals(33, sb.size());
473         assertFalse(sb.isEmpty());
474 
475         sb.minimizeCapacity();
476         assertEquals(33, sb.capacity());
477         assertEquals(33, sb.length());
478         assertEquals(33, sb.size());
479         assertFalse(sb.isEmpty());
480 
481         assertThrows(IndexOutOfBoundsException.class, () -> sb.setLength(-1));
482 
483         sb.setLength(33);
484         assertEquals(33, sb.capacity());
485         assertEquals(33, sb.length());
486         assertEquals(33, sb.size());
487         assertFalse(sb.isEmpty());
488 
489         sb.setLength(16);
490         assertTrue(sb.capacity() >= 16);
491         assertEquals(16, sb.length());
492         assertEquals(16, sb.size());
493         assertEquals("1234567890123456", sb.toString());
494         assertFalse(sb.isEmpty());
495 
496         sb.setLength(32);
497         assertTrue(sb.capacity() >= 32);
498         assertEquals(32, sb.length());
499         assertEquals(32, sb.size());
500         assertEquals("1234567890123456\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", sb.toString());
501         assertFalse(sb.isEmpty());
502 
503         sb.setLength(0);
504         assertTrue(sb.capacity() >= 32);
505         assertEquals(0, sb.length());
506         assertEquals(0, sb.size());
507         assertTrue(sb.isEmpty());
508     }
509 
510     @Test
511     public void testChaining() {
512         final TextStringBuilder sb = new TextStringBuilder();
513         assertSame(sb, sb.setNewLineText(null));
514         assertSame(sb, sb.setNullText(null));
515         assertSame(sb, sb.setLength(1));
516         assertSame(sb, sb.setCharAt(0, 'a'));
517         assertSame(sb, sb.ensureCapacity(0));
518         assertSame(sb, sb.minimizeCapacity());
519         assertSame(sb, sb.clear());
520         assertSame(sb, sb.reverse());
521         assertSame(sb, sb.trim());
522     }
523 
524     @Test
525     public void testCharAt() {
526         final TextStringBuilder sb = new TextStringBuilder();
527         assertThrows(IndexOutOfBoundsException.class, () -> sb.charAt(0));
528         assertThrows(IndexOutOfBoundsException.class, () -> sb.charAt(-1));
529         sb.append("foo");
530         assertEquals('f', sb.charAt(0));
531         assertEquals('o', sb.charAt(1));
532         assertEquals('o', sb.charAt(2));
533         assertThrows(IndexOutOfBoundsException.class, () -> sb.charAt(-1));
534         assertThrows(IndexOutOfBoundsException.class, () -> sb.charAt(3));
535     }
536 
537     @Test
538     public void testClear() {
539         final TextStringBuilder sb = new TextStringBuilder();
540         sb.append("Hello");
541         sb.clear();
542         assertEquals(0, sb.length());
543         assertTrue(sb.getBuffer().length >= 5);
544     }
545 
546     @Test
547     public void testConstructorCharSequence() {
548         final CharBuffer str = CharBuffer.wrap("A");
549         final int length = str.length();
550         final TextStringBuilder sb = new TextStringBuilder(str);
551         assertEquals(TextStringBuilder.CAPACITY + length, sb.capacity());
552         assertEquals(length, sb.toCharArray().length);
553     }
554 
555     @Test
556     public void testConstructorDefault() {
557         final TextStringBuilder sb = new TextStringBuilder();
558         assertEquals(TextStringBuilder.CAPACITY, sb.capacity());
559         assertEquals(0, sb.toCharArray().length);
560     }
561 
562     @Test
563     public void testConstructors() {
564         final TextStringBuilder sb0 = new TextStringBuilder();
565         assertEquals(32, sb0.capacity());
566         assertEquals(0, sb0.length());
567         assertEquals(0, sb0.size());
568 
569         final TextStringBuilder sb1 = new TextStringBuilder(32);
570         assertEquals(32, sb1.capacity());
571         assertEquals(0, sb1.length());
572         assertEquals(0, sb1.size());
573 
574         final TextStringBuilder sb2 = new TextStringBuilder(0);
575         assertEquals(32, sb2.capacity());
576         assertEquals(0, sb2.length());
577         assertEquals(0, sb2.size());
578 
579         final TextStringBuilder sb3 = new TextStringBuilder(-1);
580         assertEquals(32, sb3.capacity());
581         assertEquals(0, sb3.length());
582         assertEquals(0, sb3.size());
583 
584         final TextStringBuilder sb4 = new TextStringBuilder(1);
585         assertEquals(1, sb4.capacity());
586         assertEquals(0, sb4.length());
587         assertEquals(0, sb4.size());
588 
589         final TextStringBuilder sb5 = new TextStringBuilder((String) null);
590         assertEquals(32, sb5.capacity());
591         assertEquals(0, sb5.length());
592         assertEquals(0, sb5.size());
593 
594         final TextStringBuilder sb6 = new TextStringBuilder("");
595         assertEquals(32, sb6.capacity());
596         assertEquals(0, sb6.length());
597         assertEquals(0, sb6.size());
598 
599         final TextStringBuilder sb7 = new TextStringBuilder("foo");
600         assertEquals(35, sb7.capacity());
601         assertEquals(3, sb7.length());
602         assertEquals(3, sb7.size());
603     }
604 
605     @Test
606     public void testConstructorString() {
607         final String str = "A";
608         final int length = str.length();
609         final TextStringBuilder sb = new TextStringBuilder(str);
610         assertEquals(TextStringBuilder.CAPACITY + length, sb.capacity());
611         assertEquals(length, sb.toCharArray().length);
612     }
613 
614     @Test
615     public void testContains_char() {
616         final TextStringBuilder sb = new TextStringBuilder("abcdefghijklmnopqrstuvwxyz");
617         assertTrue(sb.contains('a'));
618         assertTrue(sb.contains('o'));
619         assertTrue(sb.contains('z'));
620         assertFalse(sb.contains('1'));
621     }
622 
623     @Test
624     public void testContains_String() {
625         final TextStringBuilder sb = new TextStringBuilder("abcdefghijklmnopqrstuvwxyz");
626         assertTrue(sb.contains("a"));
627         assertTrue(sb.contains("pq"));
628         assertTrue(sb.contains("z"));
629         assertFalse(sb.contains("zyx"));
630         assertFalse(sb.contains((String) null));
631     }
632 
633     @Test
634     public void testContains_StringMatcher() {
635         TextStringBuilder sb = new TextStringBuilder("abcdefghijklmnopqrstuvwxyz");
636         assertTrue(sb.contains(StringMatcherFactory.INSTANCE.charMatcher('a')));
637         assertTrue(sb.contains(StringMatcherFactory.INSTANCE.stringMatcher("pq")));
638         assertTrue(sb.contains(StringMatcherFactory.INSTANCE.charMatcher('z')));
639         assertFalse(sb.contains(StringMatcherFactory.INSTANCE.stringMatcher("zy")));
640         assertFalse(sb.contains((StringMatcher) null));
641 
642         sb = new TextStringBuilder();
643         assertFalse(sb.contains(A_NUMBER_MATCHER));
644         sb.append("B A1 C");
645         assertTrue(sb.contains(A_NUMBER_MATCHER));
646     }
647 
648     @Test
649     public void testDeleteAll_char() {
650         TextStringBuilder sb = new TextStringBuilder("abcbccba");
651         sb.deleteAll('X');
652         assertEquals("abcbccba", sb.toString());
653         sb.deleteAll('a');
654         assertEquals("bcbccb", sb.toString());
655         sb.deleteAll('c');
656         assertEquals("bbb", sb.toString());
657         sb.deleteAll('b');
658         assertEquals("", sb.toString());
659 
660         sb = new TextStringBuilder("");
661         sb.deleteAll('b');
662         assertEquals("", sb.toString());
663     }
664 
665     @Test
666     public void testDeleteAll_String() {
667         TextStringBuilder sb = new TextStringBuilder("abcbccba");
668         sb.deleteAll((String) null);
669         assertEquals("abcbccba", sb.toString());
670         sb.deleteAll("");
671         assertEquals("abcbccba", sb.toString());
672 
673         sb.deleteAll("X");
674         assertEquals("abcbccba", sb.toString());
675         sb.deleteAll("a");
676         assertEquals("bcbccb", sb.toString());
677         sb.deleteAll("c");
678         assertEquals("bbb", sb.toString());
679         sb.deleteAll("b");
680         assertEquals("", sb.toString());
681 
682         sb = new TextStringBuilder("abcbccba");
683         sb.deleteAll("bc");
684         assertEquals("acba", sb.toString());
685 
686         sb = new TextStringBuilder("");
687         sb.deleteAll("bc");
688         assertEquals("", sb.toString());
689     }
690 
691     @Test
692     public void testDeleteAll_StringMatcher() {
693         TextStringBuilder sb = new TextStringBuilder("A0xA1A2yA3");
694         sb.deleteAll((StringMatcher) null);
695         assertEquals("A0xA1A2yA3", sb.toString());
696         sb.deleteAll(A_NUMBER_MATCHER);
697         assertEquals("xy", sb.toString());
698 
699         sb = new TextStringBuilder("Ax1");
700         sb.deleteAll(A_NUMBER_MATCHER);
701         assertEquals("Ax1", sb.toString());
702 
703         sb = new TextStringBuilder("");
704         sb.deleteAll(A_NUMBER_MATCHER);
705         assertEquals("", sb.toString());
706     }
707 
708     @Test
709     public void testDeleteCharAt() {
710         final String str = "abc";
711         //
712         final TextStringBuilder sb1 = new TextStringBuilder(str);
713         sb1.deleteCharAt(0);
714         assertEquals("bc", sb1.toString());
715         //
716         final TextStringBuilder sb2 = new TextStringBuilder(str);
717         sb2.deleteCharAt(str.length() - 1);
718         assertEquals("ab", sb2.toString());
719         //
720         final TextStringBuilder sb3 = new TextStringBuilder(str);
721         assertThrows(IndexOutOfBoundsException.class, () -> sb3.deleteCharAt(str.length()));
722         assertThrows(IndexOutOfBoundsException.class, () -> sb3.deleteCharAt(1000));
723     }
724 
725     @Test
726     public void testDeleteCharAtWithNegative() {
727         assertThatExceptionOfType(StringIndexOutOfBoundsException.class).isThrownBy(() -> new TextStringBuilder().deleteCharAt(-1258));
728     }
729 
730     @Test
731     public void testDeleteFirst_char() {
732         TextStringBuilder sb = new TextStringBuilder("abcba");
733         sb.deleteFirst('X');
734         assertEquals("abcba", sb.toString());
735         sb.deleteFirst('a');
736         assertEquals("bcba", sb.toString());
737         sb.deleteFirst('c');
738         assertEquals("bba", sb.toString());
739         sb.deleteFirst('b');
740         assertEquals("ba", sb.toString());
741 
742         sb = new TextStringBuilder("");
743         sb.deleteFirst('b');
744         assertEquals("", sb.toString());
745     }
746 
747     @Test
748     public void testDeleteFirst_String() {
749         TextStringBuilder sb = new TextStringBuilder("abcbccba");
750         sb.deleteFirst((String) null);
751         assertEquals("abcbccba", sb.toString());
752         sb.deleteFirst("");
753         assertEquals("abcbccba", sb.toString());
754 
755         sb.deleteFirst("X");
756         assertEquals("abcbccba", sb.toString());
757         sb.deleteFirst("a");
758         assertEquals("bcbccba", sb.toString());
759         sb.deleteFirst("c");
760         assertEquals("bbccba", sb.toString());
761         sb.deleteFirst("b");
762         assertEquals("bccba", sb.toString());
763 
764         sb = new TextStringBuilder("abcbccba");
765         sb.deleteFirst("bc");
766         assertEquals("abccba", sb.toString());
767 
768         sb = new TextStringBuilder("");
769         sb.deleteFirst("bc");
770         assertEquals("", sb.toString());
771     }
772 
773     @Test
774     public void testDeleteFirst_StringMatcher() {
775         TextStringBuilder sb = new TextStringBuilder("A0xA1A2yA3");
776         sb.deleteFirst((StringMatcher) null);
777         assertEquals("A0xA1A2yA3", sb.toString());
778         sb.deleteFirst(A_NUMBER_MATCHER);
779         assertEquals("xA1A2yA3", sb.toString());
780 
781         sb = new TextStringBuilder("Ax1");
782         sb.deleteFirst(A_NUMBER_MATCHER);
783         assertEquals("Ax1", sb.toString());
784 
785         sb = new TextStringBuilder("");
786         sb.deleteFirst(A_NUMBER_MATCHER);
787         assertEquals("", sb.toString());
788     }
789 
790     @Test
791     public void testDeleteIntInt() {
792         final TextStringBuilder sb = new TextStringBuilder("abc");
793         sb.delete(0, 1);
794         assertEquals("bc", sb.toString());
795         sb.delete(1, 2);
796         assertEquals("b", sb.toString());
797         sb.delete(0, 1);
798         assertEquals("", sb.toString());
799         sb.delete(0, 1000);
800         assertEquals("", sb.toString());
801 
802         assertThrows(IndexOutOfBoundsException.class, () -> sb.delete(1, 2));
803         assertThrows(IndexOutOfBoundsException.class, () -> sb.delete(-1, 1));
804 
805         assertThrows(IndexOutOfBoundsException.class, () -> new TextStringBuilder("anything").delete(2, 1));
806     }
807 
808     @Test
809     public void testDrainChar() {
810         final String str = "abc";
811         //
812         final TextStringBuilder sb1 = new TextStringBuilder(str);
813         assertEquals('a', sb1.drainChar(0));
814         assertEquals("bc", sb1.toString());
815         //
816         final TextStringBuilder sb2 = new TextStringBuilder(str);
817         assertEquals('c', sb2.drainChar(str.length() - 1));
818         assertEquals("ab", sb2.toString());
819         //
820         final TextStringBuilder sb3 = new TextStringBuilder(str);
821         assertThrows(IndexOutOfBoundsException.class, () -> sb3.drainChar(str.length()));
822         assertThrows(IndexOutOfBoundsException.class, () -> sb3.drainChar(1000));
823     }
824 
825     @Test
826     public void testDrainCharsIntIntCharArrayInt() {
827         final String data = "junit";
828         final char[] array = new char[data.length()];
829         final TextStringBuilder sb = new TextStringBuilder();
830         // empty buffer
831         assertEquals(0, sb.drainChars(0, 5, array, 1));
832         assertEquals(0, sb.drainChars(0, 5, ArrayUtils.EMPTY_CHAR_ARRAY, 1));
833         // empty buffer, 0 length request
834         assertEquals(0, sb.drainChars(5, 5, array, 1));
835 
836         sb.append(data);
837         assertEquals(0, sb.drainChars(5, 5, array, 1));
838         assertEquals(5, sb.drainChars(0, 5, array, 0));
839         assertArrayEquals(data.toCharArray(), array);
840 
841         final char[] b = new char[5];
842         sb.set(data);
843         assertEquals(2, sb.drainChars(0, 2, b, 3));
844         assertArrayEquals(new char[] {0, 0, 0, 'j', 'u'}, b);
845 
846         assertThrows(IndexOutOfBoundsException.class, () -> sb.drainChars(-1, 0, b, 0));
847         assertThrows(IndexOutOfBoundsException.class, () -> sb.drainChars(0, -1, array, 0));
848         assertThrows(IndexOutOfBoundsException.class, () -> sb.drainChars(4, 2, array, 0));
849 
850         // get and delete it all.
851         sb.set(data);
852         assertEquals(data.length(), sb.drainChars(0, sb.length() + 1, array, 0));
853         assertArrayEquals(data.toCharArray(), array);
854 
855         // get and delete more than there is
856         sb.set(data);
857         assertEquals(data.length(), sb.drainChars(0, sb.length() + 10, array, 0));
858         assertArrayEquals(data.toCharArray(), array);
859 
860         // get and delete more than can fit
861         sb.set(data);
862         int targetIndex = 1;
863         Arrays.fill(array, '-');
864         assertEquals(data.length() - targetIndex, sb.drainChars(0, sb.length() + 10, array, targetIndex));
865         assertArrayEquals("-juni".toCharArray(), array);
866 
867         // get and delete more than can fit
868         sb.set(data);
869         Arrays.fill(array, '-');
870         assertEquals(data.length() - targetIndex, sb.drainChars(0, sb.length() + 1, array, targetIndex));
871         assertArrayEquals("-juni".toCharArray(), array);
872 
873         // get and delete more than can fit
874         sb.set(data);
875         targetIndex = 2;
876         Arrays.fill(array, '-');
877         assertEquals(data.length() - targetIndex, sb.drainChars(0, sb.length() + 1, array, targetIndex));
878         assertArrayEquals("--jun".toCharArray(), array);
879     }
880 
881     @Test
882     public void testEndsWith() {
883         final TextStringBuilder sb = new TextStringBuilder();
884         assertFalse(sb.endsWith("a"));
885         assertFalse(sb.endsWith("c"));
886         assertTrue(sb.endsWith(""));
887         assertFalse(sb.endsWith(null));
888         sb.append("abc");
889         assertTrue(sb.endsWith("c"));
890         assertTrue(sb.endsWith("bc"));
891         assertTrue(sb.endsWith("abc"));
892         assertFalse(sb.endsWith("cba"));
893         assertFalse(sb.endsWith("abcd"));
894         assertFalse(sb.endsWith(" abc"));
895         assertFalse(sb.endsWith("abc "));
896     }
897 
898     @Test
899     public void testEnsureCapacity() {
900         final TextStringBuilder sb = new TextStringBuilder();
901         sb.ensureCapacity(2);
902         assertTrue(sb.capacity() >= 2);
903 
904         sb.ensureCapacity(-1);
905         assertTrue(sb.capacity() >= 0);
906 
907         sb.append("HelloWorld");
908         sb.ensureCapacity(40);
909         assertTrue(sb.capacity() >= 40);
910     }
911 
912     @Test
913     public void testEnsureCapacityOutOfMemoryError() {
914         final TextStringBuilder sb = new TextStringBuilder();
915         // Should not be a NegativeArraySizeException
916         sb.ensureCapacity(Integer.MIN_VALUE);
917         sb.ensureCapacity(-1);
918         sb.ensureCapacity(0);
919         // Might fail in a CI:
920         // sb.ensureCapacity(Integer.MAX_VALUE / 2);
921         sb.ensureCapacity(10_000);
922         assertThrows(OutOfMemoryError.class, () -> sb.ensureCapacity(Integer.MAX_VALUE));
923     }
924 
925     @Test
926     public void testEquals() {
927         final TextStringBuilder sb1 = new TextStringBuilder(50);
928         final TextStringBuilder sb2 = new TextStringBuilder(100);
929         assertTrue(sb1.equals(sb2));
930         assertTrue(sb1.equals(sb1));
931         assertTrue(sb2.equals(sb2));
932         assertEquals(sb1, sb2);
933 
934         sb1.append("abc");
935         assertFalse(sb1.equals(sb2));
936         assertNotEquals(sb1, sb2);
937 
938         sb2.append("ABC");
939         assertFalse(sb1.equals(sb2));
940         assertNotEquals(sb1, sb2);
941 
942         sb2.set("abc");
943         assertTrue(sb1.equals(sb2));
944         assertEquals(sb1, sb2);
945 
946         assertNotEquals(sb1, Integer.valueOf(1));
947         assertNotEquals("abc", sb1);
948     }
949 
950     @Test
951     public void testEqualsIgnoreCase() {
952         final TextStringBuilder sb1 = new TextStringBuilder();
953         final TextStringBuilder sb2 = new TextStringBuilder();
954         assertTrue(sb1.equalsIgnoreCase(sb1));
955         assertTrue(sb1.equalsIgnoreCase(sb2));
956         assertTrue(sb2.equalsIgnoreCase(sb2));
957 
958         sb1.append("abc");
959         assertFalse(sb1.equalsIgnoreCase(sb2));
960 
961         sb2.append("ABC");
962         assertTrue(sb1.equalsIgnoreCase(sb2));
963 
964         sb2.set("abc");
965         assertTrue(sb1.equalsIgnoreCase(sb2));
966         assertTrue(sb1.equalsIgnoreCase(sb1));
967         assertTrue(sb2.equalsIgnoreCase(sb2));
968 
969         sb2.set("aBc");
970         assertTrue(sb1.equalsIgnoreCase(sb2));
971 
972         final Locale turkish = Locale.forLanguageTag("tr");
973         assertTrue(
974             new TextStringBuilder("title").equalsIgnoreCase(new TextStringBuilder("title".toLowerCase(turkish))));
975         assertTrue(
976             new TextStringBuilder("title").equalsIgnoreCase(new TextStringBuilder("TITLE".toLowerCase(turkish))));
977         assertTrue(
978             new TextStringBuilder("TITLE").equalsIgnoreCase(new TextStringBuilder("TITLE".toLowerCase(turkish))));
979         assertTrue(
980             new TextStringBuilder("TITLE").equalsIgnoreCase(new TextStringBuilder("title".toLowerCase(turkish))));
981         //
982         // assertTrue(new TextStringBuilder("title").equalsIgnoreCase(new
983         // TextStringBuilder("title".toUpperCase(turkish))));
984         // assertTrue(new TextStringBuilder("title").equalsIgnoreCase(new
985         // TextStringBuilder("TITLE".toUpperCase(turkish))));
986         assertTrue(
987             new TextStringBuilder("TITLE").equalsIgnoreCase(new TextStringBuilder("TITLE".toUpperCase(turkish))));
988         // assertTrue(new TextStringBuilder("TITLE").equalsIgnoreCase(new
989         // TextStringBuilder("title".toUpperCase(turkish))));
990     }
991 
992     @Test
993     public void testGetChars() {
994         final TextStringBuilder sb = new TextStringBuilder();
995 
996         char[] input = new char[10];
997         char[] a = sb.getChars(input);
998         assertSame(input, a);
999         assertArrayEquals(new char[10], a);
1000 
1001         sb.append("junit");
1002         a = sb.getChars(input);
1003         assertSame(input, a);
1004         assertArrayEquals(new char[] {'j', 'u', 'n', 'i', 't', 0, 0, 0, 0, 0}, a);
1005 
1006         a = sb.getChars(null);
1007         assertNotSame(input, a);
1008         assertEquals(5, a.length);
1009         assertArrayEquals("junit".toCharArray(), a);
1010 
1011         input = new char[5];
1012         a = sb.getChars(input);
1013         assertSame(input, a);
1014 
1015         input = new char[4];
1016         a = sb.getChars(input);
1017         assertNotSame(input, a);
1018     }
1019 
1020     @Test
1021     public void testGetCharsIntIntCharArrayInt() {
1022         final TextStringBuilder sb = new TextStringBuilder();
1023 
1024         final char[] array1 = new char[1];
1025         sb.getChars(0, 0, array1, 0);
1026         assertArrayEquals(new char[1], array1);
1027 
1028         sb.set("junit");
1029         sb.getChars(0, 1, array1, 0);
1030         assertArrayEquals(new char[] {'j'}, array1);
1031 
1032         final char[] array = new char[5];
1033         sb.getChars(0, 5, array, 0);
1034         assertArrayEquals(new char[] {'j', 'u', 'n', 'i', 't'}, array);
1035 
1036         final char[] b = new char[5];
1037         sb.getChars(0, 2, b, 3);
1038         assertArrayEquals(new char[] {0, 0, 0, 'j', 'u'}, b);
1039 
1040         assertThrows(IndexOutOfBoundsException.class, () -> sb.getChars(-1, 0, b, 0));
1041         assertThrows(IndexOutOfBoundsException.class, () -> sb.getChars(0, -1, array, 0));
1042         assertThrows(IndexOutOfBoundsException.class, () -> sb.getChars(0, 20, array, 0));
1043         assertThrows(IndexOutOfBoundsException.class, () -> sb.getChars(4, 2, array, 0));
1044     }
1045 
1046     @Test
1047     public void testGetSetNewLineText() {
1048         final TextStringBuilder sb = new TextStringBuilder();
1049         assertNull(sb.getNewLineText());
1050 
1051         sb.setNewLineText("#");
1052         assertEquals("#", sb.getNewLineText());
1053 
1054         sb.setNewLineText("");
1055         assertEquals("", sb.getNewLineText());
1056 
1057         sb.setNewLineText((String) null);
1058         assertNull(sb.getNewLineText());
1059     }
1060 
1061     @Test
1062     public void testGetSetNullText() {
1063         final TextStringBuilder sb = new TextStringBuilder();
1064         assertNull(sb.getNullText());
1065 
1066         sb.setNullText("null");
1067         assertEquals("null", sb.getNullText());
1068 
1069         sb.setNullText("");
1070         assertNull(sb.getNullText());
1071 
1072         sb.setNullText("NULL");
1073         assertEquals("NULL", sb.getNullText());
1074 
1075         sb.setNullText((String) null);
1076         assertNull(sb.getNullText());
1077     }
1078 
1079     @Test
1080     public void testHashCode() {
1081         final TextStringBuilder sb = new TextStringBuilder();
1082         final int hc1a = sb.hashCode();
1083         final int hc1b = sb.hashCode();
1084         assertEquals(hc1a, hc1b);
1085 
1086         // following TEXT-211 : the hash code of the buffer may not be equals to the hash code of the TextStringBuilder itself
1087         final int emptyHc = Arrays.hashCode(sb.getBuffer());
1088         assertNotEquals(emptyHc, hc1a);
1089 
1090         sb.append("abc");
1091         final int hc2a = sb.hashCode();
1092         final int hc2b = sb.hashCode();
1093         assertEquals(hc2a, hc2b);
1094 
1095         final TextStringBuilder sb2 = new TextStringBuilder(100);
1096         final TextStringBuilder sb3 = new TextStringBuilder(10);
1097         final int hc2 = sb2.hashCode();
1098         final int hc3 = sb3.hashCode();
1099         assertEquals(hc2, hc3);
1100 
1101         sb2.append("abc");
1102         sb3.append("abc");
1103         final int hc2b2 = sb2.hashCode();
1104         final int hc3b2 = sb3.hashCode();
1105         assertEquals(hc2b2, hc3b2);
1106     }
1107 
1108     @Test
1109     public void testIndexOf_char() {
1110         final TextStringBuilder sb = new TextStringBuilder("abab");
1111         assertEquals(0, sb.indexOf('a'));
1112 
1113         // should work like String#indexOf
1114         assertEquals("abab".indexOf('a'), sb.indexOf('a'));
1115 
1116         assertEquals(1, sb.indexOf('b'));
1117         assertEquals("abab".indexOf('b'), sb.indexOf('b'));
1118 
1119         assertEquals(-1, sb.indexOf('z'));
1120     }
1121 
1122     @Test
1123     public void testIndexOf_char_int() {
1124         TextStringBuilder sb = new TextStringBuilder("abab");
1125         assertEquals(0, sb.indexOf('a', -1));
1126         assertEquals(0, sb.indexOf('a', 0));
1127         assertEquals(2, sb.indexOf('a', 1));
1128         assertEquals(-1, sb.indexOf('a', 4));
1129         assertEquals(-1, sb.indexOf('a', 5));
1130 
1131         // should work like String#indexOf
1132         assertEquals("abab".indexOf('a', 1), sb.indexOf('a', 1));
1133 
1134         assertEquals(3, sb.indexOf('b', 2));
1135         assertEquals("abab".indexOf('b', 2), sb.indexOf('b', 2));
1136 
1137         assertEquals(-1, sb.indexOf('z', 2));
1138 
1139         sb = new TextStringBuilder("xyzabc");
1140         assertEquals(2, sb.indexOf('z', 0));
1141         assertEquals(-1, sb.indexOf('z', 3));
1142     }
1143 
1144     @Test
1145     public void testIndexOf_String() {
1146         final TextStringBuilder sb = new TextStringBuilder("abab");
1147 
1148         assertEquals(0, sb.indexOf("a"));
1149         // should work like String#indexOf
1150         assertEquals("abab".indexOf("a"), sb.indexOf("a"));
1151 
1152         assertEquals(0, sb.indexOf("ab"));
1153         // should work like String#indexOf
1154         assertEquals("abab".indexOf("ab"), sb.indexOf("ab"));
1155 
1156         assertEquals(1, sb.indexOf("b"));
1157         assertEquals("abab".indexOf("b"), sb.indexOf("b"));
1158 
1159         assertEquals(1, sb.indexOf("ba"));
1160         assertEquals("abab".indexOf("ba"), sb.indexOf("ba"));
1161 
1162         assertEquals(-1, sb.indexOf("z"));
1163 
1164         assertEquals(-1, sb.indexOf((String) null));
1165     }
1166 
1167     @Test
1168     public void testIndexOf_String_int() {
1169         TextStringBuilder sb = new TextStringBuilder("abab");
1170         assertEquals(0, sb.indexOf("a", -1));
1171         assertEquals(0, sb.indexOf("a", 0));
1172         assertEquals(2, sb.indexOf("a", 1));
1173         assertEquals(2, sb.indexOf("a", 2));
1174         assertEquals(-1, sb.indexOf("a", 3));
1175         assertEquals(-1, sb.indexOf("a", 4));
1176         assertEquals(-1, sb.indexOf("a", 5));
1177 
1178         assertEquals(-1, sb.indexOf("abcdef", 0));
1179         assertEquals(0, sb.indexOf("", 0));
1180         assertEquals(1, sb.indexOf("", 1));
1181 
1182         // should work like String#indexOf
1183         assertEquals("abab".indexOf("a", 1), sb.indexOf("a", 1));
1184 
1185         assertEquals(2, sb.indexOf("ab", 1));
1186         // should work like String#indexOf
1187         assertEquals("abab".indexOf("ab", 1), sb.indexOf("ab", 1));
1188 
1189         assertEquals(3, sb.indexOf("b", 2));
1190         assertEquals("abab".indexOf("b", 2), sb.indexOf("b", 2));
1191 
1192         assertEquals(1, sb.indexOf("ba", 1));
1193         assertEquals("abab".indexOf("ba", 2), sb.indexOf("ba", 2));
1194 
1195         assertEquals(-1, sb.indexOf("z", 2));
1196 
1197         sb = new TextStringBuilder("xyzabc");
1198         assertEquals(2, sb.indexOf("za", 0));
1199         assertEquals(-1, sb.indexOf("za", 3));
1200 
1201         assertEquals(-1, sb.indexOf((String) null, 2));
1202     }
1203 
1204     @Test
1205     public void testIndexOf_StringMatcher() {
1206         final TextStringBuilder sb = new TextStringBuilder();
1207         assertEquals(-1, sb.indexOf((StringMatcher) null));
1208         assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('a')));
1209 
1210         sb.append("ab bd");
1211         assertEquals(0, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('a')));
1212         assertEquals(1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('b')));
1213         assertEquals(2, sb.indexOf(StringMatcherFactory.INSTANCE.spaceMatcher()));
1214         assertEquals(4, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('d')));
1215         assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.noneMatcher()));
1216         assertEquals(-1, sb.indexOf((StringMatcher) null));
1217 
1218         sb.append(" A1 junction");
1219         assertEquals(6, sb.indexOf(A_NUMBER_MATCHER));
1220     }
1221 
1222     @Test
1223     public void testIndexOf_StringMatcher_int() {
1224         final TextStringBuilder sb = new TextStringBuilder();
1225         assertEquals(-1, sb.indexOf((StringMatcher) null, 2));
1226         assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), 2));
1227         assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), 0));
1228 
1229         sb.append("ab bd");
1230         assertEquals(0, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), -2));
1231         assertEquals(0, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), 0));
1232         assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), 2));
1233         assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), 20));
1234 
1235         assertEquals(1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), -1));
1236         assertEquals(1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 0));
1237         assertEquals(1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 1));
1238         assertEquals(3, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 2));
1239         assertEquals(3, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 3));
1240         assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 4));
1241         assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 5));
1242         assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 6));
1243 
1244         assertEquals(2, sb.indexOf(StringMatcherFactory.INSTANCE.spaceMatcher(), -2));
1245         assertEquals(2, sb.indexOf(StringMatcherFactory.INSTANCE.spaceMatcher(), 0));
1246         assertEquals(2, sb.indexOf(StringMatcherFactory.INSTANCE.spaceMatcher(), 2));
1247         assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.spaceMatcher(), 4));
1248         assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.spaceMatcher(), 20));
1249 
1250         assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.noneMatcher(), 0));
1251         assertEquals(-1, sb.indexOf((StringMatcher) null, 0));
1252 
1253         sb.append(" A1 junction with A2");
1254         assertEquals(6, sb.indexOf(A_NUMBER_MATCHER, 5));
1255         assertEquals(6, sb.indexOf(A_NUMBER_MATCHER, 6));
1256         assertEquals(23, sb.indexOf(A_NUMBER_MATCHER, 7));
1257         assertEquals(23, sb.indexOf(A_NUMBER_MATCHER, 22));
1258         assertEquals(23, sb.indexOf(A_NUMBER_MATCHER, 23));
1259         assertEquals(-1, sb.indexOf(A_NUMBER_MATCHER, 24));
1260     }
1261 
1262     @Test
1263     public void testIndexOfLang294() {
1264         final TextStringBuilder sb = new TextStringBuilder("onetwothree");
1265         sb.deleteFirst("three");
1266         assertEquals(-1, sb.indexOf("three"));
1267     }
1268 
1269     @Test
1270     public void testIsEmpty() {
1271         final TextStringBuilder sb = new TextStringBuilder();
1272         assertTrue(sb.isEmpty());
1273 
1274         sb.append("Hello");
1275         assertFalse(sb.isEmpty());
1276 
1277         sb.clear();
1278         assertTrue(sb.isEmpty());
1279     }
1280 
1281     @Test
1282     public void testIsNotEmpty() {
1283         final TextStringBuilder sb = new TextStringBuilder();
1284         assertFalse(sb.isNotEmpty());
1285 
1286         sb.append("Hello");
1287         assertTrue(sb.isNotEmpty());
1288 
1289         sb.clear();
1290         assertFalse(sb.isNotEmpty());
1291     }
1292 
1293     @Test
1294     public void testLang294() {
1295         final TextStringBuilder sb = new TextStringBuilder("\n%BLAH%\nDo more stuff\neven more stuff\n%BLAH%\n");
1296         sb.deleteAll("\n%BLAH%");
1297         assertEquals("\nDo more stuff\neven more stuff\n", sb.toString());
1298     }
1299 
1300     @Test
1301     public void testLang295() {
1302         final TextStringBuilder sb = new TextStringBuilder("onetwothree");
1303         sb.deleteFirst("three");
1304         assertFalse(sb.contains('h'), "The contains(char) method is looking beyond the end of the string");
1305         assertEquals(-1, sb.indexOf('h'), "The indexOf(char) method is looking beyond the end of the string");
1306     }
1307 
1308     @Test
1309     public void testLang412Left() {
1310         final TextStringBuilder sb = new TextStringBuilder();
1311         sb.appendFixedWidthPadLeft(null, 10, '*');
1312         assertEquals("**********", sb.toString(), "Failed to invoke appendFixedWidthPadLeft correctly");
1313     }
1314 
1315     @Test
1316     public void testLang412Right() {
1317         final TextStringBuilder sb = new TextStringBuilder();
1318         sb.appendFixedWidthPadRight(null, 10, '*');
1319         assertEquals("**********", sb.toString(), "Failed to invoke appendFixedWidthPadRight correctly");
1320     }
1321 
1322     @Test
1323     public void testLastIndexOf_char() {
1324         final TextStringBuilder sb = new TextStringBuilder("abab");
1325 
1326         assertEquals(2, sb.lastIndexOf('a'));
1327         // should work like String#lastIndexOf
1328         assertEquals("abab".lastIndexOf('a'), sb.lastIndexOf('a'));
1329 
1330         assertEquals(3, sb.lastIndexOf('b'));
1331         assertEquals("abab".lastIndexOf('b'), sb.lastIndexOf('b'));
1332 
1333         assertEquals(-1, sb.lastIndexOf('z'));
1334     }
1335 
1336     @Test
1337     public void testLastIndexOf_char_int() {
1338         TextStringBuilder sb = new TextStringBuilder("abab");
1339         assertEquals(-1, sb.lastIndexOf('a', -1));
1340         assertEquals(0, sb.lastIndexOf('a', 0));
1341         assertEquals(0, sb.lastIndexOf('a', 1));
1342 
1343         // should work like String#lastIndexOf
1344         assertEquals("abab".lastIndexOf('a', 1), sb.lastIndexOf('a', 1));
1345 
1346         assertEquals(1, sb.lastIndexOf('b', 2));
1347         assertEquals("abab".lastIndexOf('b', 2), sb.lastIndexOf('b', 2));
1348 
1349         assertEquals(-1, sb.lastIndexOf('z', 2));
1350 
1351         sb = new TextStringBuilder("xyzabc");
1352         assertEquals(2, sb.lastIndexOf('z', sb.length()));
1353         assertEquals(-1, sb.lastIndexOf('z', 1));
1354     }
1355 
1356     @Test
1357     public void testLastIndexOf_String() {
1358         final TextStringBuilder sb = new TextStringBuilder("abab");
1359 
1360         assertEquals(2, sb.lastIndexOf("a"));
1361         // should work like String#lastIndexOf
1362         assertEquals("abab".lastIndexOf("a"), sb.lastIndexOf("a"));
1363 
1364         assertEquals(2, sb.lastIndexOf("ab"));
1365         // should work like String#lastIndexOf
1366         assertEquals("abab".lastIndexOf("ab"), sb.lastIndexOf("ab"));
1367 
1368         assertEquals(3, sb.lastIndexOf("b"));
1369         assertEquals("abab".lastIndexOf("b"), sb.lastIndexOf("b"));
1370 
1371         assertEquals(1, sb.lastIndexOf("ba"));
1372         assertEquals("abab".lastIndexOf("ba"), sb.lastIndexOf("ba"));
1373 
1374         assertEquals(-1, sb.lastIndexOf("z"));
1375 
1376         assertEquals(-1, sb.lastIndexOf((String) null));
1377     }
1378 
1379     @Test
1380     public void testLastIndexOf_String_int() {
1381         TextStringBuilder sb = new TextStringBuilder("abab");
1382         assertEquals(-1, sb.lastIndexOf("a", -1));
1383         assertEquals(0, sb.lastIndexOf("a", 0));
1384         assertEquals(0, sb.lastIndexOf("a", 1));
1385         assertEquals(2, sb.lastIndexOf("a", 2));
1386         assertEquals(2, sb.lastIndexOf("a", 3));
1387         assertEquals(2, sb.lastIndexOf("a", 4));
1388         assertEquals(2, sb.lastIndexOf("a", 5));
1389 
1390         assertEquals(-1, sb.lastIndexOf("abcdef", 3));
1391         assertEquals("abab".lastIndexOf("", 3), sb.lastIndexOf("", 3));
1392         assertEquals("abab".lastIndexOf("", 1), sb.lastIndexOf("", 1));
1393 
1394         // should work like String#lastIndexOf
1395         assertEquals("abab".lastIndexOf("a", 1), sb.lastIndexOf("a", 1));
1396 
1397         assertEquals(0, sb.lastIndexOf("ab", 1));
1398         // should work like String#lastIndexOf
1399         assertEquals("abab".lastIndexOf("ab", 1), sb.lastIndexOf("ab", 1));
1400 
1401         assertEquals(1, sb.lastIndexOf("b", 2));
1402         assertEquals("abab".lastIndexOf("b", 2), sb.lastIndexOf("b", 2));
1403 
1404         assertEquals(1, sb.lastIndexOf("ba", 2));
1405         assertEquals("abab".lastIndexOf("ba", 2), sb.lastIndexOf("ba", 2));
1406 
1407         assertEquals(-1, sb.lastIndexOf("z", 2));
1408 
1409         sb = new TextStringBuilder("xyzabc");
1410         assertEquals(2, sb.lastIndexOf("za", sb.length()));
1411         assertEquals(-1, sb.lastIndexOf("za", 1));
1412 
1413         assertEquals(-1, sb.lastIndexOf((String) null, 2));
1414     }
1415 
1416     @Test
1417     public void testLastIndexOf_StringMatcher() {
1418         final TextStringBuilder sb = new TextStringBuilder();
1419         assertEquals(-1, sb.lastIndexOf((StringMatcher) null));
1420         assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('a')));
1421 
1422         sb.append("ab bd");
1423         assertEquals(0, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('a')));
1424         assertEquals(3, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('b')));
1425         assertEquals(2, sb.lastIndexOf(StringMatcherFactory.INSTANCE.spaceMatcher()));
1426         assertEquals(4, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('d')));
1427         assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.noneMatcher()));
1428         assertEquals(-1, sb.lastIndexOf((StringMatcher) null));
1429 
1430         sb.append(" A1 junction");
1431         assertEquals(6, sb.lastIndexOf(A_NUMBER_MATCHER));
1432     }
1433 
1434     @Test
1435     public void testLastIndexOf_StringMatcher_int() {
1436         final TextStringBuilder sb = new TextStringBuilder();
1437         assertEquals(-1, sb.lastIndexOf((StringMatcher) null, 2));
1438         assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), 2));
1439         assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), 0));
1440         assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), -1));
1441 
1442         sb.append("ab bd");
1443         assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), -2));
1444         assertEquals(0, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), 0));
1445         assertEquals(0, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), 2));
1446         assertEquals(0, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), 20));
1447 
1448         assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), -1));
1449         assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 0));
1450         assertEquals(1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 1));
1451         assertEquals(1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 2));
1452         assertEquals(3, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 3));
1453         assertEquals(3, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 4));
1454         assertEquals(3, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 5));
1455         assertEquals(3, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 6));
1456 
1457         assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.spaceMatcher(), -2));
1458         assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.spaceMatcher(), 0));
1459         assertEquals(2, sb.lastIndexOf(StringMatcherFactory.INSTANCE.spaceMatcher(), 2));
1460         assertEquals(2, sb.lastIndexOf(StringMatcherFactory.INSTANCE.spaceMatcher(), 4));
1461         assertEquals(2, sb.lastIndexOf(StringMatcherFactory.INSTANCE.spaceMatcher(), 20));
1462 
1463         assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.noneMatcher(), 0));
1464         assertEquals(-1, sb.lastIndexOf((StringMatcher) null, 0));
1465 
1466         sb.append(" A1 junction with A2");
1467         assertEquals(-1, sb.lastIndexOf(A_NUMBER_MATCHER, 5));
1468         assertEquals(-1, sb.lastIndexOf(A_NUMBER_MATCHER, 6)); // A matches, 1
1469                                                                // is outside
1470                                                                // bounds
1471         assertEquals(6, sb.lastIndexOf(A_NUMBER_MATCHER, 7));
1472         assertEquals(6, sb.lastIndexOf(A_NUMBER_MATCHER, 22));
1473         assertEquals(6, sb.lastIndexOf(A_NUMBER_MATCHER, 23)); // A matches, 2
1474                                                                // is outside
1475                                                                // bounds
1476         assertEquals(23, sb.lastIndexOf(A_NUMBER_MATCHER, 24));
1477     }
1478 
1479     @Test
1480     public void testLeftString() {
1481         final TextStringBuilder sb = new TextStringBuilder("left right");
1482         assertEquals("left", sb.leftString(4));
1483         assertEquals("", sb.leftString(0));
1484         assertEquals("", sb.leftString(-5));
1485         assertEquals("left right", sb.leftString(15));
1486     }
1487 
1488     @Test
1489     public void testLength() {
1490         final TextStringBuilder sb = new TextStringBuilder();
1491         assertEquals(0, sb.length());
1492 
1493         sb.append("Hello");
1494         assertEquals(5, sb.length());
1495     }
1496 
1497     @Test
1498     public void testMidString() {
1499         final TextStringBuilder sb = new TextStringBuilder("hello goodbye hello");
1500         assertEquals("goodbye", sb.midString(6, 7));
1501         assertEquals("hello", sb.midString(0, 5));
1502         assertEquals("hello", sb.midString(-5, 5));
1503         assertEquals("", sb.midString(0, -1));
1504         assertEquals("", sb.midString(20, 2));
1505         assertEquals("hello", sb.midString(14, 22));
1506     }
1507 
1508     @Test
1509     public void testMinimizeCapacity() {
1510         final TextStringBuilder sb = new TextStringBuilder();
1511         sb.minimizeCapacity();
1512         assertEquals(0, sb.capacity());
1513 
1514         sb.append("HelloWorld");
1515         sb.minimizeCapacity();
1516         assertEquals(10, sb.capacity());
1517     }
1518 
1519     @Test
1520     public void testOutOfMemoryError() {
1521         // This test is memory hungry requiring at least 7GiB of memory.
1522         // By default expansion will double the buffer size. If we repeat
1523         // add 1GiB of char data then we require at maximum:
1524         // 1GiB char[] data
1525         // 2GiB char[] buffer
1526         // ~4GiB char[] new buffer during reallocation
1527 
1528         // Attempts to guess the amount of free memory available using
1529         // the java.lang.Runtime/java.lang.management objects to
1530         // skip the test often did not work.
1531         // So here we just run the test and return a skip result if the
1532         // OutOfMemoryError occurs too early.
1533 
1534         final TextStringBuilder sb = new TextStringBuilder();
1535         sb.minimizeCapacity();
1536         assertEquals(0, sb.capacity());
1537 
1538         // 1GiB char[] buffer: length is roughly 1/4 the maximum array size
1539         final char[] chars = new char[1 << 29];
1540 
1541         // With infinite memory it should be possible to add this 3 times.
1542         try {
1543             for (int i = 0; i < 3; i++) {
1544                 sb.append(chars);
1545             }
1546         } catch (final OutOfMemoryError ignored) {
1547             Assumptions.abort("Not enough memory for the test");
1548         }
1549 
1550         // Now at 3/4 of the maximum array length.
1551         // Adding is not possible so we expect an OOM error.
1552         assertThrows(OutOfMemoryError.class, () -> sb.append(chars));
1553     }
1554 
1555     @Test
1556     public void testOutOfMemoryError2() {
1557         // This test is memory hungry requiring at least 4GiB of memory
1558         // in a single allocation. If not possible then skip the test.
1559 
1560         final TextStringBuilder sb = new TextStringBuilder();
1561         sb.minimizeCapacity();
1562         assertEquals(0, sb.capacity());
1563 
1564         // Allocate a lot
1565         final int small = 10;
1566         final int big = Integer.MAX_VALUE - small;
1567         final char[] extra = new char[small + 1];
1568         try {
1569             sb.ensureCapacity(big);
1570         } catch (final OutOfMemoryError ignored) {
1571             Assumptions.abort("Not enough memory for the test");
1572         }
1573 
1574         fill(sb, big);
1575 
1576         // Adding more than the maximum array size is not possible so we expect an OOM error.
1577         assertThrows(OutOfMemoryError.class, () -> sb.append(extra));
1578     }
1579 
1580     @Test
1581     public void testOutOfMemoryError3() {
1582         // This test is memory hungry requiring at least 2GiB of memory
1583         // in a single allocation. If not possible then skip the test.
1584 
1585         final TextStringBuilder sb = new TextStringBuilder();
1586         sb.minimizeCapacity();
1587         assertEquals(0, sb.capacity());
1588 
1589         final int length = 1 << 30;
1590         try {
1591             sb.ensureCapacity(length);
1592         } catch (final OutOfMemoryError ignored) {
1593             Assumptions.abort("Not enough memory for the test");
1594         }
1595 
1596         fill(sb, length);
1597 
1598         // Adding to itself requires a new buffer above the limits of an array
1599         assertThrows(OutOfMemoryError.class, () -> sb.append(sb));
1600     }
1601 
1602     @Test
1603     public void testReadFromCharBuffer() throws Exception {
1604         String s = "";
1605         for (int i = 0; i < 100; ++i) {
1606             final TextStringBuilder sb = new TextStringBuilder();
1607             final int len = sb.readFrom(CharBuffer.wrap(s));
1608 
1609             assertEquals(s.length(), len);
1610             assertEquals(s, sb.toString());
1611 
1612             s += Integer.toString(i);
1613         }
1614     }
1615 
1616     @Test
1617     public void testReadFromCharBufferAppendsToEnd() throws Exception {
1618         final TextStringBuilder sb = new TextStringBuilder("Test");
1619         sb.readFrom(CharBuffer.wrap(" 123"));
1620         assertEquals("Test 123", sb.toString());
1621     }
1622 
1623     @Test
1624     public void testReadFromReadable() throws Exception {
1625         String s = "";
1626         for (int i = 0; i < 100; ++i) {
1627             final TextStringBuilder sb = new TextStringBuilder();
1628             final int len = sb.readFrom(new MockReadable(s));
1629 
1630             assertEquals(s.length(), len);
1631             assertEquals(s, sb.toString());
1632 
1633             s += Integer.toString(i);
1634         }
1635     }
1636 
1637     @Test
1638     public void testReadFromReadableAppendsToEnd() throws Exception {
1639         final TextStringBuilder sb = new TextStringBuilder("Test");
1640         sb.readFrom(new MockReadable(" 123"));
1641         assertEquals("Test 123", sb.toString());
1642     }
1643 
1644     @Test
1645     public void testReadFromReader() throws Exception {
1646         String s = "1";
1647         for (int i = 0; i < 100; ++i) {
1648             final TextStringBuilder sb = new TextStringBuilder();
1649             final int len = sb.readFrom(new StringReader(s));
1650 
1651             assertEquals(s.length(), len);
1652             assertEquals(s, sb.toString());
1653 
1654             s += Integer.toString(i);
1655         }
1656     }
1657 
1658     @Test
1659     public void testReadFromReaderAppendsToEnd() throws Exception {
1660         final TextStringBuilder sb = new TextStringBuilder("Test");
1661         sb.readFrom(new StringReader(" 123"));
1662         assertEquals("Test 123", sb.toString());
1663     }
1664 
1665     @Test
1666     public void testReadFromReaderEmpty() throws Exception {
1667         final TextStringBuilder sb = new TextStringBuilder();
1668         final int len = sb.readFrom(new StringReader(StringUtils.EMPTY));
1669         assertEquals(-1, len);
1670         assertEquals(StringUtils.EMPTY, sb.toString());
1671     }
1672 
1673     @Test
1674     public void testReadFromReaderInt() throws Exception {
1675         String str = "";
1676         for (int i = 0; i < 100; ++i) {
1677             final TextStringBuilder sb = new TextStringBuilder();
1678             final int len = sb.readFrom(new StringReader(str), str.length());
1679 
1680             assertEquals(str.length(), len);
1681             assertEquals(str, sb.toString());
1682 
1683             str += Integer.toString(i);
1684         }
1685         //
1686         TextStringBuilder sb;
1687         int count;
1688         int target;
1689         final String source = "abc";
1690         final int sourceLen = source.length();
1691         // empty
1692         target = -1;
1693         sb = new TextStringBuilder();
1694         count = sb.readFrom(new StringReader(StringUtils.EMPTY), target);
1695         assertEquals(0, count);
1696         assertEquals(0, sb.size());
1697         assertEquals(source.substring(0, 0), sb.toString());
1698         //
1699         target = -1;
1700         sb = new TextStringBuilder();
1701         count = sb.readFrom(new StringReader(source), target);
1702         assertEquals(0, count);
1703         assertEquals(0, sb.size());
1704         assertEquals(source.substring(0, 0), sb.toString());
1705         //
1706         target = 0;
1707         sb = new TextStringBuilder();
1708         count = sb.readFrom(new StringReader(source), target);
1709         assertEquals(target, count);
1710         assertEquals(target, sb.size());
1711         assertEquals(source.substring(0, target), sb.toString());
1712         //
1713         target = 1;
1714         sb = new TextStringBuilder();
1715         count = sb.readFrom(new StringReader(source), target);
1716         assertEquals(target, count);
1717         assertEquals(target, sb.size());
1718         assertEquals(source.substring(0, target), sb.toString());
1719         //
1720         target = 2;
1721         sb = new TextStringBuilder();
1722         count = sb.readFrom(new StringReader(source), target);
1723         assertEquals(target, count);
1724         assertEquals(target, sb.size());
1725         assertEquals(source.substring(0, target), sb.toString());
1726         //
1727         target = 3;
1728         sb = new TextStringBuilder();
1729         count = sb.readFrom(new StringReader(source), target);
1730         assertEquals(target, count);
1731         assertEquals(target, sb.size());
1732         assertEquals(source.substring(0, target), sb.toString());
1733         //
1734         target = 4;
1735         sb = new TextStringBuilder();
1736         count = sb.readFrom(new StringReader(source), target);
1737         assertEquals(sourceLen, count);
1738         assertEquals(sourceLen, sb.size());
1739         assertEquals(source.substring(0, sourceLen), sb.toString());
1740     }
1741 
1742     @Test
1743     public void testReadFromReaderIntEmpty() throws Exception {
1744         final TextStringBuilder sb = new TextStringBuilder();
1745         final int len = sb.readFrom(new StringReader(StringUtils.EMPTY), 1);
1746         assertEquals(-1, len);
1747         assertEquals(StringUtils.EMPTY, sb.toString());
1748     }
1749 
1750     @Test
1751     public void testReplace_int_int_String() {
1752         final TextStringBuilder sb = new TextStringBuilder("abc");
1753         sb.replace(0, 1, "d");
1754         assertEquals("dbc", sb.toString());
1755         sb.replace(0, 1, "aaa");
1756         assertEquals("aaabc", sb.toString());
1757         sb.replace(0, 3, "");
1758         assertEquals("bc", sb.toString());
1759         sb.replace(1, 2, (String) null);
1760         assertEquals("b", sb.toString());
1761         sb.replace(1, 1000, "text");
1762         assertEquals("btext", sb.toString());
1763         sb.replace(0, 1000, "text");
1764         assertEquals("text", sb.toString());
1765 
1766         final TextStringBuilder builder = new TextStringBuilder("atext");
1767         builder.replace(1, 1, "ny");
1768         assertEquals("anytext", builder.toString());
1769 
1770         assertThrows(IndexOutOfBoundsException.class, () -> builder.replace(2, 1, "anything"));
1771 
1772         builder.clear();
1773         assertThrows(IndexOutOfBoundsException.class, () -> builder.replace(1, 2, "anything"));
1774         assertThrows(IndexOutOfBoundsException.class, () -> builder.replace(-1, 1, "anything"));
1775     }
1776 
1777     @Test
1778     public void testReplace_StringMatcher_String_int_int_int_VaryCount() {
1779         TextStringBuilder sb = new TextStringBuilder("aaxaaaayaa");
1780         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 10, -1);
1781         assertEquals("-x--y-", sb.toString());
1782 
1783         sb = new TextStringBuilder("aaxaaaayaa");
1784         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 10, 0);
1785         assertEquals("aaxaaaayaa", sb.toString());
1786 
1787         sb = new TextStringBuilder("aaxaaaayaa");
1788         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 10, 1);
1789         assertEquals("-xaaaayaa", sb.toString());
1790 
1791         sb = new TextStringBuilder("aaxaaaayaa");
1792         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 10, 2);
1793         assertEquals("-x-aayaa", sb.toString());
1794 
1795         sb = new TextStringBuilder("aaxaaaayaa");
1796         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 10, 3);
1797         assertEquals("-x--yaa", sb.toString());
1798 
1799         sb = new TextStringBuilder("aaxaaaayaa");
1800         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 10, 4);
1801         assertEquals("-x--y-", sb.toString());
1802 
1803         sb = new TextStringBuilder("aaxaaaayaa");
1804         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 10, 5);
1805         assertEquals("-x--y-", sb.toString());
1806     }
1807 
1808     @Test
1809     public void testReplace_StringMatcher_String_int_int_int_VaryEndIndex() {
1810         TextStringBuilder sb = new TextStringBuilder("aaxaaaayaa");
1811         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 0, -1);
1812         assertEquals("aaxaaaayaa", sb.toString());
1813 
1814         sb = new TextStringBuilder("aaxaaaayaa");
1815         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 2, -1);
1816         assertEquals("-xaaaayaa", sb.toString());
1817 
1818         sb = new TextStringBuilder("aaxaaaayaa");
1819         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 3, -1);
1820         assertEquals("-xaaaayaa", sb.toString());
1821 
1822         sb = new TextStringBuilder("aaxaaaayaa");
1823         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 4, -1);
1824         assertEquals("-xaaaayaa", sb.toString());
1825 
1826         sb = new TextStringBuilder("aaxaaaayaa");
1827         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 5, -1);
1828         assertEquals("-x-aayaa", sb.toString());
1829 
1830         sb = new TextStringBuilder("aaxaaaayaa");
1831         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 6, -1);
1832         assertEquals("-x-aayaa", sb.toString());
1833 
1834         sb = new TextStringBuilder("aaxaaaayaa");
1835         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 7, -1);
1836         assertEquals("-x--yaa", sb.toString());
1837 
1838         sb = new TextStringBuilder("aaxaaaayaa");
1839         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 8, -1);
1840         assertEquals("-x--yaa", sb.toString());
1841 
1842         sb = new TextStringBuilder("aaxaaaayaa");
1843         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 9, -1);
1844         assertEquals("-x--yaa", sb.toString());
1845 
1846         sb = new TextStringBuilder("aaxaaaayaa");
1847         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 10, -1);
1848         assertEquals("-x--y-", sb.toString());
1849 
1850         sb = new TextStringBuilder("aaxaaaayaa");
1851         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 1000, -1);
1852         assertEquals("-x--y-", sb.toString());
1853 
1854         final TextStringBuilder builder = new TextStringBuilder("aaxaaaayaa");
1855         assertThrows(IndexOutOfBoundsException.class,
1856             () -> builder.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 2, 1, -1));
1857         assertEquals("aaxaaaayaa", builder.toString());
1858     }
1859 
1860     @Test
1861     public void testReplace_StringMatcher_String_int_int_int_VaryMatcher() {
1862         TextStringBuilder sb = new TextStringBuilder("abcbccba");
1863         sb.replace((StringMatcher) null, "x", 0, sb.length(), -1);
1864         assertEquals("abcbccba", sb.toString());
1865 
1866         sb.replace(StringMatcherFactory.INSTANCE.charMatcher('a'), "x", 0, sb.length(), -1);
1867         assertEquals("xbcbccbx", sb.toString());
1868 
1869         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("cb"), "x", 0, sb.length(), -1);
1870         assertEquals("xbxcxx", sb.toString());
1871 
1872         sb = new TextStringBuilder("A1-A2A3-A4");
1873         sb.replace(A_NUMBER_MATCHER, "***", 0, sb.length(), -1);
1874         assertEquals("***-******-***", sb.toString());
1875 
1876         sb = new TextStringBuilder();
1877         sb.replace(A_NUMBER_MATCHER, "***", 0, sb.length(), -1);
1878         assertEquals("", sb.toString());
1879     }
1880 
1881     @Test
1882     public void testReplace_StringMatcher_String_int_int_int_VaryReplace() {
1883         TextStringBuilder sb = new TextStringBuilder("abcbccba");
1884         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("cb"), "cb", 0, sb.length(), -1);
1885         assertEquals("abcbccba", sb.toString());
1886 
1887         sb = new TextStringBuilder("abcbccba");
1888         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("cb"), "-", 0, sb.length(), -1);
1889         assertEquals("ab-c-a", sb.toString());
1890 
1891         sb = new TextStringBuilder("abcbccba");
1892         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("cb"), "+++", 0, sb.length(), -1);
1893         assertEquals("ab+++c+++a", sb.toString());
1894 
1895         sb = new TextStringBuilder("abcbccba");
1896         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("cb"), "", 0, sb.length(), -1);
1897         assertEquals("abca", sb.toString());
1898 
1899         sb = new TextStringBuilder("abcbccba");
1900         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("cb"), null, 0, sb.length(), -1);
1901         assertEquals("abca", sb.toString());
1902     }
1903 
1904     @Test
1905     public void testReplace_StringMatcher_String_int_int_int_VaryStartIndex() {
1906         TextStringBuilder sb = new TextStringBuilder("aaxaaaayaa");
1907         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, sb.length(), -1);
1908         assertEquals("-x--y-", sb.toString());
1909 
1910         sb = new TextStringBuilder("aaxaaaayaa");
1911         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 1, sb.length(), -1);
1912         assertEquals("aax--y-", sb.toString());
1913 
1914         sb = new TextStringBuilder("aaxaaaayaa");
1915         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 2, sb.length(), -1);
1916         assertEquals("aax--y-", sb.toString());
1917 
1918         sb = new TextStringBuilder("aaxaaaayaa");
1919         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 3, sb.length(), -1);
1920         assertEquals("aax--y-", sb.toString());
1921 
1922         sb = new TextStringBuilder("aaxaaaayaa");
1923         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 4, sb.length(), -1);
1924         assertEquals("aaxa-ay-", sb.toString());
1925 
1926         sb = new TextStringBuilder("aaxaaaayaa");
1927         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 5, sb.length(), -1);
1928         assertEquals("aaxaa-y-", sb.toString());
1929 
1930         sb = new TextStringBuilder("aaxaaaayaa");
1931         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 6, sb.length(), -1);
1932         assertEquals("aaxaaaay-", sb.toString());
1933 
1934         sb = new TextStringBuilder("aaxaaaayaa");
1935         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 7, sb.length(), -1);
1936         assertEquals("aaxaaaay-", sb.toString());
1937 
1938         sb = new TextStringBuilder("aaxaaaayaa");
1939         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 8, sb.length(), -1);
1940         assertEquals("aaxaaaay-", sb.toString());
1941 
1942         sb = new TextStringBuilder("aaxaaaayaa");
1943         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 9, sb.length(), -1);
1944         assertEquals("aaxaaaayaa", sb.toString());
1945 
1946         sb = new TextStringBuilder("aaxaaaayaa");
1947         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 10, sb.length(), -1);
1948         assertEquals("aaxaaaayaa", sb.toString());
1949 
1950         final TextStringBuilder builder = new TextStringBuilder("aaxaaaayaa");
1951         assertThrows(IndexOutOfBoundsException.class,
1952             () -> builder.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 11, builder.length(), -1));
1953         assertEquals("aaxaaaayaa", builder.toString());
1954 
1955         builder.set("aaxaaaayaa");
1956         assertThrows(IndexOutOfBoundsException.class,
1957             () -> builder.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", -1, builder.length(), -1));
1958         assertEquals("aaxaaaayaa", builder.toString());
1959     }
1960 
1961     @Test
1962     public void testReplaceAll_char_char() {
1963         final TextStringBuilder sb = new TextStringBuilder("abcbccba");
1964         sb.replaceAll('x', 'y');
1965         assertEquals("abcbccba", sb.toString());
1966         sb.replaceAll('a', 'd');
1967         assertEquals("dbcbccbd", sb.toString());
1968         sb.replaceAll('b', 'e');
1969         assertEquals("dececced", sb.toString());
1970         sb.replaceAll('c', 'f');
1971         assertEquals("defeffed", sb.toString());
1972         sb.replaceAll('d', 'd');
1973         assertEquals("defeffed", sb.toString());
1974     }
1975 
1976     @Test
1977     public void testReplaceAll_String_String() {
1978         TextStringBuilder sb = new TextStringBuilder("abcbccba");
1979         sb.replaceAll((String) null, null);
1980         assertEquals("abcbccba", sb.toString());
1981         sb.replaceAll((String) null, "anything");
1982         assertEquals("abcbccba", sb.toString());
1983         sb.replaceAll("", null);
1984         assertEquals("abcbccba", sb.toString());
1985         sb.replaceAll("", "anything");
1986         assertEquals("abcbccba", sb.toString());
1987 
1988         sb.replaceAll("x", "y");
1989         assertEquals("abcbccba", sb.toString());
1990         sb.replaceAll("a", "d");
1991         assertEquals("dbcbccbd", sb.toString());
1992         sb.replaceAll("d", null);
1993         assertEquals("bcbccb", sb.toString());
1994         sb.replaceAll("cb", "-");
1995         assertEquals("b-c-", sb.toString());
1996 
1997         sb = new TextStringBuilder("abcba");
1998         sb.replaceAll("b", "xbx");
1999         assertEquals("axbxcxbxa", sb.toString());
2000 
2001         sb = new TextStringBuilder("bb");
2002         sb.replaceAll("b", "xbx");
2003         assertEquals("xbxxbx", sb.toString());
2004     }
2005 
2006     @Test
2007     public void testReplaceAll_StringMatcher_String() {
2008         TextStringBuilder sb = new TextStringBuilder("abcbccba");
2009         sb.replaceAll((StringMatcher) null, null);
2010         assertEquals("abcbccba", sb.toString());
2011         sb.replaceAll((StringMatcher) null, "anything");
2012         assertEquals("abcbccba", sb.toString());
2013         sb.replaceAll(StringMatcherFactory.INSTANCE.noneMatcher(), null);
2014         assertEquals("abcbccba", sb.toString());
2015         sb.replaceAll(StringMatcherFactory.INSTANCE.noneMatcher(), "anything");
2016         assertEquals("abcbccba", sb.toString());
2017 
2018         sb.replaceAll(StringMatcherFactory.INSTANCE.charMatcher('x'), "y");
2019         assertEquals("abcbccba", sb.toString());
2020         sb.replaceAll(StringMatcherFactory.INSTANCE.charMatcher('a'), "d");
2021         assertEquals("dbcbccbd", sb.toString());
2022         sb.replaceAll(StringMatcherFactory.INSTANCE.charMatcher('d'), null);
2023         assertEquals("bcbccb", sb.toString());
2024         sb.replaceAll(StringMatcherFactory.INSTANCE.stringMatcher("cb"), "-");
2025         assertEquals("b-c-", sb.toString());
2026 
2027         sb = new TextStringBuilder("abcba");
2028         sb.replaceAll(StringMatcherFactory.INSTANCE.charMatcher('b'), "xbx");
2029         assertEquals("axbxcxbxa", sb.toString());
2030 
2031         sb = new TextStringBuilder("bb");
2032         sb.replaceAll(StringMatcherFactory.INSTANCE.charMatcher('b'), "xbx");
2033         assertEquals("xbxxbx", sb.toString());
2034 
2035         sb = new TextStringBuilder("A1-A2A3-A4");
2036         sb.replaceAll(A_NUMBER_MATCHER, "***");
2037         assertEquals("***-******-***", sb.toString());
2038 
2039         sb = new TextStringBuilder("Dear X, hello X.");
2040         sb.replaceAll(StringMatcherFactory.INSTANCE.stringMatcher("X"), "012345678901234567");
2041         assertEquals("Dear 012345678901234567, hello 012345678901234567.", sb.toString());
2042     }
2043 
2044     @Test
2045     public void testReplaceFirst_char_char() {
2046         final TextStringBuilder sb = new TextStringBuilder("abcbccba");
2047         sb.replaceFirst('x', 'y');
2048         assertEquals("abcbccba", sb.toString());
2049         sb.replaceFirst('a', 'd');
2050         assertEquals("dbcbccba", sb.toString());
2051         sb.replaceFirst('b', 'e');
2052         assertEquals("decbccba", sb.toString());
2053         sb.replaceFirst('c', 'f');
2054         assertEquals("defbccba", sb.toString());
2055         sb.replaceFirst('d', 'd');
2056         assertEquals("defbccba", sb.toString());
2057     }
2058 
2059     @Test
2060     public void testReplaceFirst_String_String() {
2061         TextStringBuilder sb = new TextStringBuilder("abcbccba");
2062         sb.replaceFirst((String) null, null);
2063         assertEquals("abcbccba", sb.toString());
2064         sb.replaceFirst((String) null, "anything");
2065         assertEquals("abcbccba", sb.toString());
2066         sb.replaceFirst("", null);
2067         assertEquals("abcbccba", sb.toString());
2068         sb.replaceFirst("", "anything");
2069         assertEquals("abcbccba", sb.toString());
2070 
2071         sb.replaceFirst("x", "y");
2072         assertEquals("abcbccba", sb.toString());
2073         sb.replaceFirst("a", "d");
2074         assertEquals("dbcbccba", sb.toString());
2075         sb.replaceFirst("d", null);
2076         assertEquals("bcbccba", sb.toString());
2077         sb.replaceFirst("cb", "-");
2078         assertEquals("b-ccba", sb.toString());
2079 
2080         sb = new TextStringBuilder("abcba");
2081         sb.replaceFirst("b", "xbx");
2082         assertEquals("axbxcba", sb.toString());
2083 
2084         sb = new TextStringBuilder("bb");
2085         sb.replaceFirst("b", "xbx");
2086         assertEquals("xbxb", sb.toString());
2087     }
2088 
2089     @Test
2090     public void testReplaceFirst_StringMatcher_String() {
2091         TextStringBuilder sb = new TextStringBuilder("abcbccba");
2092         sb.replaceFirst((StringMatcher) null, null);
2093         assertEquals("abcbccba", sb.toString());
2094         sb.replaceFirst((StringMatcher) null, "anything");
2095         assertEquals("abcbccba", sb.toString());
2096         sb.replaceFirst(StringMatcherFactory.INSTANCE.noneMatcher(), null);
2097         assertEquals("abcbccba", sb.toString());
2098         sb.replaceFirst(StringMatcherFactory.INSTANCE.noneMatcher(), "anything");
2099         assertEquals("abcbccba", sb.toString());
2100 
2101         sb.replaceFirst(StringMatcherFactory.INSTANCE.charMatcher('x'), "y");
2102         assertEquals("abcbccba", sb.toString());
2103         sb.replaceFirst(StringMatcherFactory.INSTANCE.charMatcher('a'), "d");
2104         assertEquals("dbcbccba", sb.toString());
2105         sb.replaceFirst(StringMatcherFactory.INSTANCE.charMatcher('d'), null);
2106         assertEquals("bcbccba", sb.toString());
2107         sb.replaceFirst(StringMatcherFactory.INSTANCE.stringMatcher("cb"), "-");
2108         assertEquals("b-ccba", sb.toString());
2109 
2110         sb = new TextStringBuilder("abcba");
2111         sb.replaceFirst(StringMatcherFactory.INSTANCE.charMatcher('b'), "xbx");
2112         assertEquals("axbxcba", sb.toString());
2113 
2114         sb = new TextStringBuilder("bb");
2115         sb.replaceFirst(StringMatcherFactory.INSTANCE.charMatcher('b'), "xbx");
2116         assertEquals("xbxb", sb.toString());
2117 
2118         sb = new TextStringBuilder("A1-A2A3-A4");
2119         sb.replaceFirst(A_NUMBER_MATCHER, "***");
2120         assertEquals("***-A2A3-A4", sb.toString());
2121     }
2122 
2123     @Test
2124     public void testReverse() {
2125         final TextStringBuilder sb = new TextStringBuilder();
2126         assertEquals("", sb.reverse().toString());
2127 
2128         sb.clear().append(true);
2129         assertEquals("eurt", sb.reverse().toString());
2130         assertEquals("true", sb.reverse().toString());
2131     }
2132 
2133     @Test
2134     public void testRightString() {
2135         final TextStringBuilder sb = new TextStringBuilder("left right");
2136         assertEquals("right", sb.rightString(5));
2137         assertEquals("", sb.rightString(0));
2138         assertEquals("", sb.rightString(-5));
2139         assertEquals("left right", sb.rightString(15));
2140     }
2141 
2142     @Test
2143     public void testSetCharAt() {
2144         final TextStringBuilder sb = new TextStringBuilder();
2145         assertThrows(IndexOutOfBoundsException.class, () -> sb.setCharAt(0, 'f'));
2146         assertThrows(IndexOutOfBoundsException.class, () -> sb.setCharAt(-1, 'f'));
2147         sb.append("foo");
2148         sb.setCharAt(0, 'b');
2149         sb.setCharAt(1, 'a');
2150         sb.setCharAt(2, 'r');
2151         assertThrows(IndexOutOfBoundsException.class, () -> sb.setCharAt(3, '!'));
2152         assertEquals("bar", sb.toString());
2153     }
2154 
2155     @Test
2156     public void testSetLength() {
2157         final TextStringBuilder sb = new TextStringBuilder();
2158         sb.append("Hello");
2159         sb.setLength(2); // shorten
2160         assertEquals("He", sb.toString());
2161         sb.setLength(2); // no change
2162         assertEquals("He", sb.toString());
2163         sb.setLength(3); // lengthen
2164         assertEquals("He\0", sb.toString());
2165 
2166         assertThrows(IndexOutOfBoundsException.class, () -> sb.setLength(-1));
2167     }
2168 
2169     @Test
2170     public void testSize() {
2171         final TextStringBuilder sb = new TextStringBuilder();
2172         assertEquals(0, sb.size());
2173 
2174         sb.append("Hello");
2175         assertEquals(5, sb.size());
2176     }
2177 
2178     @Test
2179     public void testStartsWith() {
2180         final TextStringBuilder sb = new TextStringBuilder();
2181         assertFalse(sb.startsWith("a"));
2182         assertFalse(sb.startsWith(null));
2183         assertTrue(sb.startsWith(""));
2184         sb.append("abc");
2185         assertTrue(sb.startsWith("a"));
2186         assertTrue(sb.startsWith("ab"));
2187         assertTrue(sb.startsWith("abc"));
2188         assertFalse(sb.startsWith("cba"));
2189     }
2190 
2191     @Test
2192     public void testSubSequenceIntInt() {
2193         final TextStringBuilder sb = new TextStringBuilder("hello goodbye");
2194         // Start index is negative
2195         assertThrows(IndexOutOfBoundsException.class, () -> sb.subSequence(-1, 5));
2196 
2197         // End index is negative
2198         assertThrows(IndexOutOfBoundsException.class, () -> sb.subSequence(2, -1));
2199 
2200         // End index greater than length()
2201         assertThrows(IndexOutOfBoundsException.class, () -> sb.subSequence(2, sb.length() + 1));
2202 
2203         // Start index greater then end index
2204         assertThrows(IndexOutOfBoundsException.class, () -> sb.subSequence(3, 2));
2205 
2206         // Normal cases
2207         assertEquals("hello", sb.subSequence(0, 5));
2208         assertEquals("hello goodbye".subSequence(0, 6), sb.subSequence(0, 6));
2209         assertEquals("goodbye", sb.subSequence(6, 13));
2210         assertEquals("hello goodbye".subSequence(6, 13), sb.subSequence(6, 13));
2211     }
2212 
2213     @Test
2214     public void testSubstringInt() {
2215         final TextStringBuilder sb = new TextStringBuilder("hello goodbye");
2216         assertEquals("goodbye", sb.substring(6));
2217         assertEquals("hello goodbye".substring(6), sb.substring(6));
2218         assertEquals("hello goodbye", sb.substring(0));
2219         assertEquals("hello goodbye".substring(0), sb.substring(0));
2220         assertThrows(IndexOutOfBoundsException.class, () -> sb.substring(-1));
2221 
2222         assertThrows(IndexOutOfBoundsException.class, () -> sb.substring(15));
2223 
2224     }
2225 
2226     @Test
2227     public void testSubstringIntInt() {
2228         final TextStringBuilder sb = new TextStringBuilder("hello goodbye");
2229         assertEquals("hello", sb.substring(0, 5));
2230         assertEquals("hello goodbye".substring(0, 6), sb.substring(0, 6));
2231 
2232         assertEquals("goodbye", sb.substring(6, 13));
2233         assertEquals("hello goodbye".substring(6, 13), sb.substring(6, 13));
2234 
2235         assertEquals("goodbye", sb.substring(6, 20));
2236 
2237         assertThrows(IndexOutOfBoundsException.class, () -> sb.substring(-1, 5));
2238 
2239         assertThrows(IndexOutOfBoundsException.class, () -> sb.substring(15, 20));
2240     }
2241 
2242     @Test
2243     public void testToCharArray() {
2244         final TextStringBuilder sb = new TextStringBuilder();
2245         assertEquals(0, sb.toCharArray().length);
2246 
2247         char[] a = sb.toCharArray();
2248         assertNotNull(a, "toCharArray() result is null");
2249         assertEquals(0, a.length, "toCharArray() result is too large");
2250 
2251         sb.append("junit");
2252         a = sb.toCharArray();
2253         assertEquals(5, a.length, "toCharArray() result incorrect length");
2254         assertArrayEquals("junit".toCharArray(), a, "toCharArray() result does not match");
2255     }
2256 
2257     @Test
2258     public void testToCharArrayIntInt() {
2259         final TextStringBuilder sb = new TextStringBuilder();
2260         assertEquals(0, sb.toCharArray(0, 0).length);
2261 
2262         sb.append("junit");
2263         char[] a = sb.toCharArray(0, 20); // too large test
2264         assertEquals(5, a.length, "toCharArray(int,int) result incorrect length");
2265         assertArrayEquals("junit".toCharArray(), a, "toCharArray(int,int) result does not match");
2266 
2267         a = sb.toCharArray(0, 4);
2268         assertEquals(4, a.length, "toCharArray(int,int) result incorrect length");
2269         assertArrayEquals("juni".toCharArray(), a, "toCharArray(int,int) result does not match");
2270 
2271         a = sb.toCharArray(0, 4);
2272         assertEquals(4, a.length, "toCharArray(int,int) result incorrect length");
2273         assertArrayEquals("juni".toCharArray(), a, "toCharArray(int,int) result does not match");
2274 
2275         a = sb.toCharArray(0, 1);
2276         assertNotNull(a, "toCharArray(int,int) result is null");
2277 
2278         assertThrows(IndexOutOfBoundsException.class, () -> sb.toCharArray(-1, 5));
2279 
2280         assertThrows(IndexOutOfBoundsException.class, () -> sb.toCharArray(6, 5));
2281     }
2282 
2283     @Test
2284     public void testToString() {
2285         final TextStringBuilder sb = new TextStringBuilder("abc");
2286         assertEquals("abc", sb.toString());
2287     }
2288 
2289     @Test
2290     public void testToStringBuffer() {
2291         final TextStringBuilder sb = new TextStringBuilder();
2292         assertEquals(new StringBuffer().toString(), sb.toStringBuffer().toString());
2293 
2294         sb.append("junit");
2295         assertEquals(new StringBuffer("junit").toString(), sb.toStringBuffer().toString());
2296     }
2297 
2298     @Test
2299     public void testToStringBuilder() {
2300         final TextStringBuilder sb = new TextStringBuilder();
2301         assertEquals(new StringBuilder().toString(), sb.toStringBuilder().toString());
2302 
2303         sb.append("junit");
2304         assertEquals(new StringBuilder("junit").toString(), sb.toStringBuilder().toString());
2305     }
2306 
2307     @Test
2308     public void testTrim() {
2309         final TextStringBuilder sb = new TextStringBuilder();
2310         assertEquals("", sb.reverse().toString());
2311 
2312         sb.set(" \u0000 ");
2313         assertEquals("", sb.trim().toString());
2314 
2315         sb.set(" \u0000 a b c");
2316         assertEquals("a b c", sb.trim().toString());
2317 
2318         sb.set("a b c \u0000 ");
2319         assertEquals("a b c", sb.trim().toString());
2320 
2321         sb.set(" \u0000 a b c \u0000 ");
2322         assertEquals("a b c", sb.trim().toString());
2323 
2324         sb.set("a b c");
2325         assertEquals("a b c", sb.trim().toString());
2326     }
2327 
2328     @Test
2329     public void testWrap_CharArray() {
2330         assertThrows(NullPointerException.class, () -> TextStringBuilder.wrap(null));
2331         //
2332         final TextStringBuilder initEmpty = TextStringBuilder.wrap(ArrayUtils.EMPTY_CHAR_ARRAY);
2333         assertEquals(0, initEmpty.size());
2334         assertEquals(0, initEmpty.length());
2335         initEmpty.append('a');
2336         assertEquals(1, initEmpty.size());
2337         assertEquals(1, initEmpty.length());
2338         //
2339         final char[] test = "abc".toCharArray();
2340         final TextStringBuilder builder = TextStringBuilder.wrap(test);
2341         assertArrayEquals(test, builder.getBuffer());
2342         assertEquals(test.length, builder.length());
2343         assertEquals(test.length, builder.size());
2344         assertFalse(builder.isReallocated());
2345         builder.ensureCapacity(builder.capacity() * 2);
2346         assertFalse(Arrays.equals(test, builder.getBuffer()));
2347         assertTrue(builder.isReallocated());
2348     }
2349 
2350     private void testWrap_CharArray_Int(final String test, final int expectedLen) {
2351         final char[] input = "abc".toCharArray();
2352         final TextStringBuilder builder = TextStringBuilder.wrap(input, expectedLen);
2353         assertArrayEquals(input, builder.getBuffer());
2354         assertEquals(expectedLen, builder.length());
2355         assertEquals(expectedLen, builder.size());
2356         assertFalse(builder.isReallocated());
2357         builder.ensureCapacity(builder.capacity() * 2);
2358         assertFalse(Arrays.equals(input, builder.getBuffer()));
2359         assertTrue(builder.isReallocated());
2360     }
2361 
2362     @Test
2363     public void testWrap_CharArray_Int_0() {
2364         testWrap_CharArray_Int("abc", 0);
2365     }
2366 
2367     @Test
2368     public void testWrap_CharArray_Int_1() {
2369         testWrap_CharArray_Int("abc", 1);
2370     }
2371 
2372     @Test
2373     public void testWrap_CharArray_Int_2() {
2374         testWrap_CharArray_Int("abc", 2);
2375     }
2376 
2377     @Test
2378     public void testWrap_CharArray_Int_3() {
2379         testWrap_CharArray_Int("abc", 3);
2380     }
2381 
2382     @Test
2383     public void testWrap_CharArray_Int_Empty_0() {
2384         final TextStringBuilder initEmpty = TextStringBuilder.wrap(ArrayUtils.EMPTY_CHAR_ARRAY, 0);
2385         assertEquals(0, initEmpty.size());
2386         assertEquals(0, initEmpty.length());
2387         initEmpty.append('a');
2388         assertEquals(1, initEmpty.size());
2389         assertEquals(1, initEmpty.length());
2390     }
2391 
2392     @Test
2393     public void testWrap_CharArray_Int_Exceptions() {
2394         assertThrows(NullPointerException.class, () -> TextStringBuilder.wrap(null, 0));
2395         assertThrows(IllegalArgumentException.class, () -> TextStringBuilder.wrap("abc".toCharArray(), -1));
2396         assertThrows(IllegalArgumentException.class, () -> TextStringBuilder.wrap(ArrayUtils.EMPTY_CHAR_ARRAY, 1));
2397     }
2398 
2399 }