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