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    *      https://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  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     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     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     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     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     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     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     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     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     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     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     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     void testAppendToStringBuffer() throws Exception {
248         final TextStringBuilder sb = new TextStringBuilder("1234567890");
249         final StringBuffer buffer = new StringBuffer("Test ");
250 
251         sb.appendTo(buffer);
252 
253         assertEquals("Test 1234567890", buffer.toString());
254     }
255 
256     @Test
257     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     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     void testAsBuilder() {
279         final TextStringBuilder sb = new TextStringBuilder().appendAll("Lorem", " ", "ipsum", " ", "dolor");
280         assertEquals(sb.toString(), sb.build());
281     }
282 
283     @Test
284     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     void testAsSupplier() {
343         final TextStringBuilder sb = new TextStringBuilder().appendAll("Lorem", " ", "ipsum", " ", "dolor");
344         assertEquals(sb.toString(), sb.get());
345     }
346 
347     @Test
348     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     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     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     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     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     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     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     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     void testConstructorCharSequenceNull() {
555         final TextStringBuilder sb = new TextStringBuilder((CharSequence) null);
556         assertEquals(TextStringBuilder.CAPACITY, sb.capacity());
557         assertEquals(0, sb.toCharArray().length);
558     }
559 
560     @Test
561     void testConstructorDefault() {
562         final TextStringBuilder sb = new TextStringBuilder();
563         assertEquals(TextStringBuilder.CAPACITY, sb.capacity());
564         assertEquals(0, sb.toCharArray().length);
565     }
566 
567     @Test
568     void testConstructors() {
569         final TextStringBuilder sb0 = new TextStringBuilder();
570         assertEquals(32, sb0.capacity());
571         assertEquals(0, sb0.length());
572         assertEquals(0, sb0.size());
573 
574         final TextStringBuilder sb1 = new TextStringBuilder(32);
575         assertEquals(32, sb1.capacity());
576         assertEquals(0, sb1.length());
577         assertEquals(0, sb1.size());
578 
579         final TextStringBuilder sb2 = new TextStringBuilder(0);
580         assertEquals(32, sb2.capacity());
581         assertEquals(0, sb2.length());
582         assertEquals(0, sb2.size());
583 
584         final TextStringBuilder sb3 = new TextStringBuilder(-1);
585         assertEquals(32, sb3.capacity());
586         assertEquals(0, sb3.length());
587         assertEquals(0, sb3.size());
588 
589         final TextStringBuilder sb4 = new TextStringBuilder(1);
590         assertEquals(1, sb4.capacity());
591         assertEquals(0, sb4.length());
592         assertEquals(0, sb4.size());
593 
594         final TextStringBuilder sb5 = new TextStringBuilder((String) null);
595         assertEquals(32, sb5.capacity());
596         assertEquals(0, sb5.length());
597         assertEquals(0, sb5.size());
598 
599         final TextStringBuilder sb6 = new TextStringBuilder("");
600         assertEquals(32, sb6.capacity());
601         assertEquals(0, sb6.length());
602         assertEquals(0, sb6.size());
603 
604         final TextStringBuilder sb7 = new TextStringBuilder("foo");
605         assertEquals(35, sb7.capacity());
606         assertEquals(3, sb7.length());
607         assertEquals(3, sb7.size());
608     }
609 
610     @Test
611     void testConstructorString() {
612         final String str = "A";
613         final int length = str.length();
614         final TextStringBuilder sb = new TextStringBuilder(str);
615         assertEquals(TextStringBuilder.CAPACITY + length, sb.capacity());
616         assertEquals(length, sb.toCharArray().length);
617     }
618 
619     @Test
620     void testContains_char() {
621         final TextStringBuilder sb = new TextStringBuilder("abcdefghijklmnopqrstuvwxyz");
622         assertTrue(sb.contains('a'));
623         assertTrue(sb.contains('o'));
624         assertTrue(sb.contains('z'));
625         assertFalse(sb.contains('1'));
626     }
627 
628     @Test
629     void testContains_String() {
630         final TextStringBuilder sb = new TextStringBuilder("abcdefghijklmnopqrstuvwxyz");
631         assertTrue(sb.contains("a"));
632         assertTrue(sb.contains("pq"));
633         assertTrue(sb.contains("z"));
634         assertFalse(sb.contains("zyx"));
635         assertFalse(sb.contains((String) null));
636     }
637 
638     @Test
639     void testContains_StringMatcher() {
640         TextStringBuilder sb = new TextStringBuilder("abcdefghijklmnopqrstuvwxyz");
641         assertTrue(sb.contains(StringMatcherFactory.INSTANCE.charMatcher('a')));
642         assertTrue(sb.contains(StringMatcherFactory.INSTANCE.stringMatcher("pq")));
643         assertTrue(sb.contains(StringMatcherFactory.INSTANCE.charMatcher('z')));
644         assertFalse(sb.contains(StringMatcherFactory.INSTANCE.stringMatcher("zy")));
645         assertFalse(sb.contains((StringMatcher) null));
646 
647         sb = new TextStringBuilder();
648         assertFalse(sb.contains(A_NUMBER_MATCHER));
649         sb.append("B A1 C");
650         assertTrue(sb.contains(A_NUMBER_MATCHER));
651     }
652 
653     @Test
654     void testDeleteAll_char() {
655         TextStringBuilder sb = new TextStringBuilder("abcbccba");
656         sb.deleteAll('X');
657         assertEquals("abcbccba", sb.toString());
658         sb.deleteAll('a');
659         assertEquals("bcbccb", sb.toString());
660         sb.deleteAll('c');
661         assertEquals("bbb", sb.toString());
662         sb.deleteAll('b');
663         assertEquals("", sb.toString());
664 
665         sb = new TextStringBuilder("");
666         sb.deleteAll('b');
667         assertEquals("", sb.toString());
668     }
669 
670     @Test
671     void testDeleteAll_String() {
672         TextStringBuilder sb = new TextStringBuilder("abcbccba");
673         sb.deleteAll((String) null);
674         assertEquals("abcbccba", sb.toString());
675         sb.deleteAll("");
676         assertEquals("abcbccba", sb.toString());
677 
678         sb.deleteAll("X");
679         assertEquals("abcbccba", sb.toString());
680         sb.deleteAll("a");
681         assertEquals("bcbccb", sb.toString());
682         sb.deleteAll("c");
683         assertEquals("bbb", sb.toString());
684         sb.deleteAll("b");
685         assertEquals("", sb.toString());
686 
687         sb = new TextStringBuilder("abcbccba");
688         sb.deleteAll("bc");
689         assertEquals("acba", sb.toString());
690 
691         sb = new TextStringBuilder("");
692         sb.deleteAll("bc");
693         assertEquals("", sb.toString());
694     }
695 
696     @Test
697     void testDeleteAll_StringMatcher() {
698         TextStringBuilder sb = new TextStringBuilder("A0xA1A2yA3");
699         sb.deleteAll((StringMatcher) null);
700         assertEquals("A0xA1A2yA3", sb.toString());
701         sb.deleteAll(A_NUMBER_MATCHER);
702         assertEquals("xy", sb.toString());
703 
704         sb = new TextStringBuilder("Ax1");
705         sb.deleteAll(A_NUMBER_MATCHER);
706         assertEquals("Ax1", sb.toString());
707 
708         sb = new TextStringBuilder("");
709         sb.deleteAll(A_NUMBER_MATCHER);
710         assertEquals("", sb.toString());
711     }
712 
713     @Test
714     void testDeleteCharAt() {
715         final String str = "abc";
716         //
717         final TextStringBuilder sb1 = new TextStringBuilder(str);
718         sb1.deleteCharAt(0);
719         assertEquals("bc", sb1.toString());
720         //
721         final TextStringBuilder sb2 = new TextStringBuilder(str);
722         sb2.deleteCharAt(str.length() - 1);
723         assertEquals("ab", sb2.toString());
724         //
725         final TextStringBuilder sb3 = new TextStringBuilder(str);
726         assertThrows(IndexOutOfBoundsException.class, () -> sb3.deleteCharAt(str.length()));
727         assertThrows(IndexOutOfBoundsException.class, () -> sb3.deleteCharAt(1000));
728     }
729 
730     @Test
731     void testDeleteCharAtWithNegative() {
732         assertThrows(StringIndexOutOfBoundsException.class, () -> new TextStringBuilder().deleteCharAt(-1258));
733     }
734 
735     @Test
736     void testDeleteFirst_char() {
737         TextStringBuilder sb = new TextStringBuilder("abcba");
738         sb.deleteFirst('X');
739         assertEquals("abcba", sb.toString());
740         sb.deleteFirst('a');
741         assertEquals("bcba", sb.toString());
742         sb.deleteFirst('c');
743         assertEquals("bba", sb.toString());
744         sb.deleteFirst('b');
745         assertEquals("ba", sb.toString());
746 
747         sb = new TextStringBuilder("");
748         sb.deleteFirst('b');
749         assertEquals("", sb.toString());
750     }
751 
752     @Test
753     void testDeleteFirst_String() {
754         TextStringBuilder sb = new TextStringBuilder("abcbccba");
755         sb.deleteFirst((String) null);
756         assertEquals("abcbccba", sb.toString());
757         sb.deleteFirst("");
758         assertEquals("abcbccba", sb.toString());
759 
760         sb.deleteFirst("X");
761         assertEquals("abcbccba", sb.toString());
762         sb.deleteFirst("a");
763         assertEquals("bcbccba", sb.toString());
764         sb.deleteFirst("c");
765         assertEquals("bbccba", sb.toString());
766         sb.deleteFirst("b");
767         assertEquals("bccba", sb.toString());
768 
769         sb = new TextStringBuilder("abcbccba");
770         sb.deleteFirst("bc");
771         assertEquals("abccba", sb.toString());
772 
773         sb = new TextStringBuilder("");
774         sb.deleteFirst("bc");
775         assertEquals("", sb.toString());
776     }
777 
778     @Test
779     void testDeleteFirst_StringMatcher() {
780         TextStringBuilder sb = new TextStringBuilder("A0xA1A2yA3");
781         sb.deleteFirst((StringMatcher) null);
782         assertEquals("A0xA1A2yA3", sb.toString());
783         sb.deleteFirst(A_NUMBER_MATCHER);
784         assertEquals("xA1A2yA3", sb.toString());
785 
786         sb = new TextStringBuilder("Ax1");
787         sb.deleteFirst(A_NUMBER_MATCHER);
788         assertEquals("Ax1", sb.toString());
789 
790         sb = new TextStringBuilder("");
791         sb.deleteFirst(A_NUMBER_MATCHER);
792         assertEquals("", sb.toString());
793     }
794 
795     @Test
796     void testDeleteIntInt() {
797         final TextStringBuilder sb = new TextStringBuilder("abc");
798         sb.delete(0, 1);
799         assertEquals("bc", sb.toString());
800         sb.delete(1, 2);
801         assertEquals("b", sb.toString());
802         sb.delete(0, 1);
803         assertEquals("", sb.toString());
804         sb.delete(0, 1000);
805         assertEquals("", sb.toString());
806 
807         assertThrows(IndexOutOfBoundsException.class, () -> sb.delete(1, 2));
808         assertThrows(IndexOutOfBoundsException.class, () -> sb.delete(-1, 1));
809 
810         assertThrows(IndexOutOfBoundsException.class, () -> new TextStringBuilder("anything").delete(2, 1));
811     }
812 
813     @Test
814     void testDrainChar() {
815         final String str = "abc";
816         //
817         final TextStringBuilder sb1 = new TextStringBuilder(str);
818         assertEquals('a', sb1.drainChar(0));
819         assertEquals("bc", sb1.toString());
820         //
821         final TextStringBuilder sb2 = new TextStringBuilder(str);
822         assertEquals('c', sb2.drainChar(str.length() - 1));
823         assertEquals("ab", sb2.toString());
824         //
825         final TextStringBuilder sb3 = new TextStringBuilder(str);
826         assertThrows(IndexOutOfBoundsException.class, () -> sb3.drainChar(str.length()));
827         assertThrows(IndexOutOfBoundsException.class, () -> sb3.drainChar(1000));
828     }
829 
830     @Test
831     void testDrainCharsIntIntCharArrayInt() {
832         final String data = "junit";
833         final char[] array = new char[data.length()];
834         final TextStringBuilder sb = new TextStringBuilder();
835         // empty buffer
836         assertEquals(0, sb.drainChars(0, 5, array, 1));
837         assertEquals(0, sb.drainChars(0, 5, ArrayUtils.EMPTY_CHAR_ARRAY, 1));
838         // empty buffer, 0 length request
839         assertEquals(0, sb.drainChars(5, 5, array, 1));
840 
841         sb.append(data);
842         assertEquals(0, sb.drainChars(5, 5, array, 1));
843         assertEquals(5, sb.drainChars(0, 5, array, 0));
844         assertArrayEquals(data.toCharArray(), array);
845 
846         final char[] b = new char[5];
847         sb.set(data);
848         assertEquals(2, sb.drainChars(0, 2, b, 3));
849         assertArrayEquals(new char[] { 0, 0, 0, 'j', 'u' }, b);
850 
851         assertThrows(IndexOutOfBoundsException.class, () -> sb.drainChars(-1, 0, b, 0));
852         assertThrows(IndexOutOfBoundsException.class, () -> sb.drainChars(0, -1, array, 0));
853         assertThrows(IndexOutOfBoundsException.class, () -> sb.drainChars(4, 2, array, 0));
854 
855         // get and delete it all.
856         sb.set(data);
857         assertEquals(data.length(), sb.drainChars(0, sb.length() + 1, array, 0));
858         assertArrayEquals(data.toCharArray(), array);
859 
860         // get and delete more than there is
861         sb.set(data);
862         assertEquals(data.length(), sb.drainChars(0, sb.length() + 10, array, 0));
863         assertArrayEquals(data.toCharArray(), array);
864 
865         // get and delete more than can fit
866         sb.set(data);
867         int targetIndex = 1;
868         Arrays.fill(array, '-');
869         assertEquals(data.length() - targetIndex, sb.drainChars(0, sb.length() + 10, array, targetIndex));
870         assertArrayEquals("-juni".toCharArray(), array);
871 
872         // get and delete more than can fit
873         sb.set(data);
874         Arrays.fill(array, '-');
875         assertEquals(data.length() - targetIndex, sb.drainChars(0, sb.length() + 1, array, targetIndex));
876         assertArrayEquals("-juni".toCharArray(), array);
877 
878         // get and delete more than can fit
879         sb.set(data);
880         targetIndex = 2;
881         Arrays.fill(array, '-');
882         assertEquals(data.length() - targetIndex, sb.drainChars(0, sb.length() + 1, array, targetIndex));
883         assertArrayEquals("--jun".toCharArray(), array);
884     }
885 
886     @Test
887     void testEndsWith() {
888         final TextStringBuilder sb = new TextStringBuilder();
889         assertFalse(sb.endsWith("a"));
890         assertFalse(sb.endsWith("c"));
891         assertTrue(sb.endsWith(""));
892         assertFalse(sb.endsWith(null));
893         sb.append("abc");
894         assertTrue(sb.endsWith("c"));
895         assertTrue(sb.endsWith("bc"));
896         assertTrue(sb.endsWith("abc"));
897         assertFalse(sb.endsWith("cba"));
898         assertFalse(sb.endsWith("abcd"));
899         assertFalse(sb.endsWith(" abc"));
900         assertFalse(sb.endsWith("abc "));
901     }
902 
903     @Test
904     void testEnsureCapacity() {
905         final TextStringBuilder sb = new TextStringBuilder();
906         sb.ensureCapacity(2);
907         assertTrue(sb.capacity() >= 2);
908 
909         sb.ensureCapacity(-1);
910         assertTrue(sb.capacity() >= 0);
911 
912         sb.append("HelloWorld");
913         sb.ensureCapacity(40);
914         assertTrue(sb.capacity() >= 40);
915     }
916 
917     @Test
918     void testEnsureCapacityOutOfMemoryError() {
919         final TextStringBuilder sb = new TextStringBuilder();
920         // Should not be a NegativeArraySizeException
921         sb.ensureCapacity(Integer.MIN_VALUE);
922         sb.ensureCapacity(-1);
923         sb.ensureCapacity(0);
924         // Might fail in a CI:
925         // sb.ensureCapacity(Integer.MAX_VALUE / 2);
926         sb.ensureCapacity(10_000);
927         assertThrows(OutOfMemoryError.class, () -> sb.ensureCapacity(Integer.MAX_VALUE));
928     }
929 
930     @Test
931     void testEquals() {
932         final TextStringBuilder sb1 = new TextStringBuilder(50);
933         final TextStringBuilder sb2 = new TextStringBuilder(100);
934         assertTrue(sb1.equals(sb2));
935         assertTrue(sb1.equals(sb1));
936         assertTrue(sb2.equals(sb2));
937         assertEquals(sb1, sb2);
938 
939         sb1.append("abc");
940         assertFalse(sb1.equals(sb2));
941         assertNotEquals(sb1, sb2);
942 
943         sb2.append("ABC");
944         assertFalse(sb1.equals(sb2));
945         assertNotEquals(sb1, sb2);
946 
947         sb2.set("abc");
948         assertTrue(sb1.equals(sb2));
949         assertEquals(sb1, sb2);
950 
951         assertNotEquals(sb1, Integer.valueOf(1));
952         assertNotEquals("abc", sb1);
953     }
954 
955     @Test
956     void testEqualsIgnoreCase() {
957         final TextStringBuilder sb1 = new TextStringBuilder();
958         final TextStringBuilder sb2 = new TextStringBuilder();
959         assertTrue(sb1.equalsIgnoreCase(sb1));
960         assertTrue(sb1.equalsIgnoreCase(sb2));
961         assertTrue(sb2.equalsIgnoreCase(sb2));
962 
963         sb1.append("abc");
964         assertFalse(sb1.equalsIgnoreCase(sb2));
965 
966         sb2.append("ABC");
967         assertTrue(sb1.equalsIgnoreCase(sb2));
968 
969         sb2.set("abc");
970         assertTrue(sb1.equalsIgnoreCase(sb2));
971         assertTrue(sb1.equalsIgnoreCase(sb1));
972         assertTrue(sb2.equalsIgnoreCase(sb2));
973 
974         sb2.set("aBc");
975         assertTrue(sb1.equalsIgnoreCase(sb2));
976 
977         final Locale turkish = Locale.forLanguageTag("tr");
978         assertTrue(new TextStringBuilder("title").equalsIgnoreCase(new TextStringBuilder("title".toLowerCase(turkish))));
979         assertTrue(new TextStringBuilder("title").equalsIgnoreCase(new TextStringBuilder("TITLE".toLowerCase(turkish))));
980         assertTrue(new TextStringBuilder("TITLE").equalsIgnoreCase(new TextStringBuilder("TITLE".toLowerCase(turkish))));
981         assertTrue(new TextStringBuilder("TITLE").equalsIgnoreCase(new TextStringBuilder("title".toLowerCase(turkish))));
982         //
983         // assertTrue(new TextStringBuilder("title").equalsIgnoreCase(new
984         // TextStringBuilder("title".toUpperCase(turkish))));
985         // assertTrue(new TextStringBuilder("title").equalsIgnoreCase(new
986         // TextStringBuilder("TITLE".toUpperCase(turkish))));
987         assertTrue(new TextStringBuilder("TITLE").equalsIgnoreCase(new TextStringBuilder("TITLE".toUpperCase(turkish))));
988         // assertTrue(new TextStringBuilder("TITLE").equalsIgnoreCase(new
989         // TextStringBuilder("title".toUpperCase(turkish))));
990     }
991 
992     @Test
993     void testErrorMessageShowsCorrectVariable() {
994         final TextStringBuilder sb = new TextStringBuilder("Hello");
995         final char[] chars = { 'a', 'b', 'c' };
996         StringIndexOutOfBoundsException ex = assertThrows(StringIndexOutOfBoundsException.class, () -> sb.append(chars, 1, 4));
997         assertTrue(ex.getMessage().contains("length: 4"));
998         ex = assertThrows(StringIndexOutOfBoundsException.class, () -> sb.append(chars, 7, 3));
999         assertTrue(ex.getMessage().contains("startIndex: 7"));
1000     }
1001 
1002     @Test
1003     void testGetChars() {
1004         final TextStringBuilder sb = new TextStringBuilder();
1005 
1006         char[] input = new char[10];
1007         char[] a = sb.getChars(input);
1008         assertSame(input, a);
1009         assertArrayEquals(new char[10], a);
1010 
1011         sb.append("junit");
1012         a = sb.getChars(input);
1013         assertSame(input, a);
1014         assertArrayEquals(new char[] { 'j', 'u', 'n', 'i', 't', 0, 0, 0, 0, 0 }, a);
1015 
1016         a = sb.getChars(null);
1017         assertNotSame(input, a);
1018         assertEquals(5, a.length);
1019         assertArrayEquals("junit".toCharArray(), a);
1020 
1021         input = new char[5];
1022         a = sb.getChars(input);
1023         assertSame(input, a);
1024 
1025         input = new char[4];
1026         a = sb.getChars(input);
1027         assertNotSame(input, a);
1028     }
1029 
1030     @Test
1031     void testGetCharsIntIntCharArrayInt() {
1032         final TextStringBuilder sb = new TextStringBuilder();
1033 
1034         final char[] array1 = new char[1];
1035         sb.getChars(0, 0, array1, 0);
1036         assertArrayEquals(new char[1], array1);
1037 
1038         sb.set("junit");
1039         sb.getChars(0, 1, array1, 0);
1040         assertArrayEquals(new char[] { 'j' }, array1);
1041 
1042         final char[] array = new char[5];
1043         sb.getChars(0, 5, array, 0);
1044         assertArrayEquals(new char[] { 'j', 'u', 'n', 'i', 't' }, array);
1045 
1046         final char[] b = new char[5];
1047         sb.getChars(0, 2, b, 3);
1048         assertArrayEquals(new char[] { 0, 0, 0, 'j', 'u' }, b);
1049 
1050         assertThrows(IndexOutOfBoundsException.class, () -> sb.getChars(-1, 0, b, 0));
1051         assertThrows(IndexOutOfBoundsException.class, () -> sb.getChars(0, -1, array, 0));
1052         assertThrows(IndexOutOfBoundsException.class, () -> sb.getChars(0, 20, array, 0));
1053         assertThrows(IndexOutOfBoundsException.class, () -> sb.getChars(4, 2, array, 0));
1054     }
1055 
1056     @Test
1057     void testGetSetNewLineText() {
1058         final TextStringBuilder sb = new TextStringBuilder();
1059         assertNull(sb.getNewLineText());
1060 
1061         sb.setNewLineText("#");
1062         assertEquals("#", sb.getNewLineText());
1063 
1064         sb.setNewLineText("");
1065         assertEquals("", sb.getNewLineText());
1066 
1067         sb.setNewLineText((String) null);
1068         assertNull(sb.getNewLineText());
1069     }
1070 
1071     @Test
1072     void testGetSetNullText() {
1073         final TextStringBuilder sb = new TextStringBuilder();
1074         assertNull(sb.getNullText());
1075 
1076         sb.setNullText("null");
1077         assertEquals("null", sb.getNullText());
1078 
1079         sb.setNullText("");
1080         assertNull(sb.getNullText());
1081 
1082         sb.setNullText("NULL");
1083         assertEquals("NULL", sb.getNullText());
1084 
1085         sb.setNullText((String) null);
1086         assertNull(sb.getNullText());
1087     }
1088 
1089     @Test
1090     void testHashCode() {
1091         final TextStringBuilder sb = new TextStringBuilder();
1092         final int hc1a = sb.hashCode();
1093         final int hc1b = sb.hashCode();
1094         assertEquals(hc1a, hc1b);
1095 
1096         // following TEXT-211 : the hash code of the buffer may not be equals to the hash code of the TextStringBuilder itself
1097         final int emptyHc = Arrays.hashCode(sb.getBuffer());
1098         assertNotEquals(emptyHc, hc1a);
1099 
1100         sb.append("abc");
1101         final int hc2a = sb.hashCode();
1102         final int hc2b = sb.hashCode();
1103         assertEquals(hc2a, hc2b);
1104 
1105         final TextStringBuilder sb2 = new TextStringBuilder(100);
1106         final TextStringBuilder sb3 = new TextStringBuilder(10);
1107         final int hc2 = sb2.hashCode();
1108         final int hc3 = sb3.hashCode();
1109         assertEquals(hc2, hc3);
1110 
1111         sb2.append("abc");
1112         sb3.append("abc");
1113         final int hc2b2 = sb2.hashCode();
1114         final int hc3b2 = sb3.hashCode();
1115         assertEquals(hc2b2, hc3b2);
1116     }
1117 
1118     @Test
1119     void testIndexOf_char() {
1120         final TextStringBuilder sb = new TextStringBuilder("abab");
1121         assertEquals(0, sb.indexOf('a'));
1122 
1123         // should work like String#indexOf
1124         assertEquals("abab".indexOf('a'), sb.indexOf('a'));
1125 
1126         assertEquals(1, sb.indexOf('b'));
1127         assertEquals("abab".indexOf('b'), sb.indexOf('b'));
1128 
1129         assertEquals(-1, sb.indexOf('z'));
1130     }
1131 
1132     @Test
1133     void testIndexOf_char_int() {
1134         TextStringBuilder sb = new TextStringBuilder("abab");
1135         assertEquals(0, sb.indexOf('a', -1));
1136         assertEquals(0, sb.indexOf('a', 0));
1137         assertEquals(2, sb.indexOf('a', 1));
1138         assertEquals(-1, sb.indexOf('a', 4));
1139         assertEquals(-1, sb.indexOf('a', 5));
1140 
1141         // should work like String#indexOf
1142         assertEquals("abab".indexOf('a', 1), sb.indexOf('a', 1));
1143 
1144         assertEquals(3, sb.indexOf('b', 2));
1145         assertEquals("abab".indexOf('b', 2), sb.indexOf('b', 2));
1146 
1147         assertEquals(-1, sb.indexOf('z', 2));
1148 
1149         sb = new TextStringBuilder("xyzabc");
1150         assertEquals(2, sb.indexOf('z', 0));
1151         assertEquals(-1, sb.indexOf('z', 3));
1152     }
1153 
1154     @Test
1155     void testIndexOf_String() {
1156         final TextStringBuilder sb = new TextStringBuilder("abab");
1157 
1158         assertEquals(0, sb.indexOf("a"));
1159         // should work like String#indexOf
1160         assertEquals("abab".indexOf("a"), sb.indexOf("a"));
1161 
1162         assertEquals(0, sb.indexOf("ab"));
1163         // should work like String#indexOf
1164         assertEquals("abab".indexOf("ab"), sb.indexOf("ab"));
1165 
1166         assertEquals(1, sb.indexOf("b"));
1167         assertEquals("abab".indexOf("b"), sb.indexOf("b"));
1168 
1169         assertEquals(1, sb.indexOf("ba"));
1170         assertEquals("abab".indexOf("ba"), sb.indexOf("ba"));
1171 
1172         assertEquals(-1, sb.indexOf("z"));
1173 
1174         assertEquals(-1, sb.indexOf((String) null));
1175     }
1176 
1177     @Test
1178     void testIndexOf_String_int() {
1179         TextStringBuilder sb = new TextStringBuilder("abab");
1180         assertEquals(0, sb.indexOf("a", -1));
1181         assertEquals(0, sb.indexOf("a", 0));
1182         assertEquals(2, sb.indexOf("a", 1));
1183         assertEquals(2, sb.indexOf("a", 2));
1184         assertEquals(-1, sb.indexOf("a", 3));
1185         assertEquals(-1, sb.indexOf("a", 4));
1186         assertEquals(-1, sb.indexOf("a", 5));
1187 
1188         assertEquals(-1, sb.indexOf("abcdef", 0));
1189         assertEquals(0, sb.indexOf("", 0));
1190         assertEquals(1, sb.indexOf("", 1));
1191 
1192         // should work like String#indexOf
1193         assertEquals("abab".indexOf("a", 1), sb.indexOf("a", 1));
1194 
1195         assertEquals(2, sb.indexOf("ab", 1));
1196         // should work like String#indexOf
1197         assertEquals("abab".indexOf("ab", 1), sb.indexOf("ab", 1));
1198 
1199         assertEquals(3, sb.indexOf("b", 2));
1200         assertEquals("abab".indexOf("b", 2), sb.indexOf("b", 2));
1201 
1202         assertEquals(1, sb.indexOf("ba", 1));
1203         assertEquals("abab".indexOf("ba", 2), sb.indexOf("ba", 2));
1204 
1205         assertEquals(-1, sb.indexOf("z", 2));
1206 
1207         sb = new TextStringBuilder("xyzabc");
1208         assertEquals(2, sb.indexOf("za", 0));
1209         assertEquals(-1, sb.indexOf("za", 3));
1210 
1211         assertEquals(-1, sb.indexOf((String) null, 2));
1212     }
1213 
1214     @Test
1215     void testIndexOf_StringMatcher() {
1216         final TextStringBuilder sb = new TextStringBuilder();
1217         assertEquals(-1, sb.indexOf((StringMatcher) null));
1218         assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('a')));
1219 
1220         sb.append("ab bd");
1221         assertEquals(0, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('a')));
1222         assertEquals(1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('b')));
1223         assertEquals(2, sb.indexOf(StringMatcherFactory.INSTANCE.spaceMatcher()));
1224         assertEquals(4, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('d')));
1225         assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.noneMatcher()));
1226         assertEquals(-1, sb.indexOf((StringMatcher) null));
1227 
1228         sb.append(" A1 junction");
1229         assertEquals(6, sb.indexOf(A_NUMBER_MATCHER));
1230     }
1231 
1232     @Test
1233     void testIndexOf_StringMatcher_int() {
1234         final TextStringBuilder sb = new TextStringBuilder();
1235         assertEquals(-1, sb.indexOf((StringMatcher) null, 2));
1236         assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), 2));
1237         assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), 0));
1238 
1239         sb.append("ab bd");
1240         assertEquals(0, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), -2));
1241         assertEquals(0, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), 0));
1242         assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), 2));
1243         assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), 20));
1244 
1245         assertEquals(1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), -1));
1246         assertEquals(1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 0));
1247         assertEquals(1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 1));
1248         assertEquals(3, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 2));
1249         assertEquals(3, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 3));
1250         assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 4));
1251         assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 5));
1252         assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 6));
1253 
1254         assertEquals(2, sb.indexOf(StringMatcherFactory.INSTANCE.spaceMatcher(), -2));
1255         assertEquals(2, sb.indexOf(StringMatcherFactory.INSTANCE.spaceMatcher(), 0));
1256         assertEquals(2, sb.indexOf(StringMatcherFactory.INSTANCE.spaceMatcher(), 2));
1257         assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.spaceMatcher(), 4));
1258         assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.spaceMatcher(), 20));
1259 
1260         assertEquals(-1, sb.indexOf(StringMatcherFactory.INSTANCE.noneMatcher(), 0));
1261         assertEquals(-1, sb.indexOf((StringMatcher) null, 0));
1262 
1263         sb.append(" A1 junction with A2");
1264         assertEquals(6, sb.indexOf(A_NUMBER_MATCHER, 5));
1265         assertEquals(6, sb.indexOf(A_NUMBER_MATCHER, 6));
1266         assertEquals(23, sb.indexOf(A_NUMBER_MATCHER, 7));
1267         assertEquals(23, sb.indexOf(A_NUMBER_MATCHER, 22));
1268         assertEquals(23, sb.indexOf(A_NUMBER_MATCHER, 23));
1269         assertEquals(-1, sb.indexOf(A_NUMBER_MATCHER, 24));
1270     }
1271 
1272     @Test
1273     void testIndexOfLang294() {
1274         final TextStringBuilder sb = new TextStringBuilder("onetwothree");
1275         sb.deleteFirst("three");
1276         assertEquals(-1, sb.indexOf("three"));
1277     }
1278 
1279     @Test
1280     void testIsEmpty() {
1281         final TextStringBuilder sb = new TextStringBuilder();
1282         assertTrue(sb.isEmpty());
1283 
1284         sb.append("Hello");
1285         assertFalse(sb.isEmpty());
1286 
1287         sb.clear();
1288         assertTrue(sb.isEmpty());
1289     }
1290 
1291     @Test
1292     void testIsNotEmpty() {
1293         final TextStringBuilder sb = new TextStringBuilder();
1294         assertFalse(sb.isNotEmpty());
1295 
1296         sb.append("Hello");
1297         assertTrue(sb.isNotEmpty());
1298 
1299         sb.clear();
1300         assertFalse(sb.isNotEmpty());
1301     }
1302 
1303     @Test
1304     void testLang294() {
1305         final TextStringBuilder sb = new TextStringBuilder("\n%BLAH%\nDo more stuff\neven more stuff\n%BLAH%\n");
1306         sb.deleteAll("\n%BLAH%");
1307         assertEquals("\nDo more stuff\neven more stuff\n", sb.toString());
1308     }
1309 
1310     @Test
1311     void testLang295() {
1312         final TextStringBuilder sb = new TextStringBuilder("onetwothree");
1313         sb.deleteFirst("three");
1314         assertFalse(sb.contains('h'), "The contains(char) method is looking beyond the end of the string");
1315         assertEquals(-1, sb.indexOf('h'), "The indexOf(char) method is looking beyond the end of the string");
1316     }
1317 
1318     @Test
1319     void testLang412Left() {
1320         final TextStringBuilder sb = new TextStringBuilder();
1321         sb.appendFixedWidthPadLeft(null, 10, '*');
1322         assertEquals("**********", sb.toString(), "Failed to invoke appendFixedWidthPadLeft correctly");
1323     }
1324 
1325     @Test
1326     void testLang412Right() {
1327         final TextStringBuilder sb = new TextStringBuilder();
1328         sb.appendFixedWidthPadRight(null, 10, '*');
1329         assertEquals("**********", sb.toString(), "Failed to invoke appendFixedWidthPadRight correctly");
1330     }
1331 
1332     @Test
1333     void testLastIndexOf_char() {
1334         final TextStringBuilder sb = new TextStringBuilder("abab");
1335 
1336         assertEquals(2, sb.lastIndexOf('a'));
1337         // should work like String#lastIndexOf
1338         assertEquals("abab".lastIndexOf('a'), sb.lastIndexOf('a'));
1339 
1340         assertEquals(3, sb.lastIndexOf('b'));
1341         assertEquals("abab".lastIndexOf('b'), sb.lastIndexOf('b'));
1342 
1343         assertEquals(-1, sb.lastIndexOf('z'));
1344     }
1345 
1346     @Test
1347     void testLastIndexOf_char_int() {
1348         TextStringBuilder sb = new TextStringBuilder("abab");
1349         assertEquals(-1, sb.lastIndexOf('a', -1));
1350         assertEquals(0, sb.lastIndexOf('a', 0));
1351         assertEquals(0, sb.lastIndexOf('a', 1));
1352 
1353         // should work like String#lastIndexOf
1354         assertEquals("abab".lastIndexOf('a', 1), sb.lastIndexOf('a', 1));
1355 
1356         assertEquals(1, sb.lastIndexOf('b', 2));
1357         assertEquals("abab".lastIndexOf('b', 2), sb.lastIndexOf('b', 2));
1358 
1359         assertEquals(-1, sb.lastIndexOf('z', 2));
1360 
1361         sb = new TextStringBuilder("xyzabc");
1362         assertEquals(2, sb.lastIndexOf('z', sb.length()));
1363         assertEquals(-1, sb.lastIndexOf('z', 1));
1364     }
1365 
1366     @Test
1367     void testLastIndexOf_String() {
1368         final TextStringBuilder sb = new TextStringBuilder("abab");
1369 
1370         assertEquals(2, sb.lastIndexOf("a"));
1371         // should work like String#lastIndexOf
1372         assertEquals("abab".lastIndexOf("a"), sb.lastIndexOf("a"));
1373 
1374         assertEquals(2, sb.lastIndexOf("ab"));
1375         // should work like String#lastIndexOf
1376         assertEquals("abab".lastIndexOf("ab"), sb.lastIndexOf("ab"));
1377 
1378         assertEquals(3, sb.lastIndexOf("b"));
1379         assertEquals("abab".lastIndexOf("b"), sb.lastIndexOf("b"));
1380 
1381         assertEquals(1, sb.lastIndexOf("ba"));
1382         assertEquals("abab".lastIndexOf("ba"), sb.lastIndexOf("ba"));
1383 
1384         assertEquals(-1, sb.lastIndexOf("z"));
1385 
1386         assertEquals(-1, sb.lastIndexOf((String) null));
1387     }
1388 
1389     @Test
1390     void testLastIndexOf_String_int() {
1391         TextStringBuilder sb = new TextStringBuilder("abab");
1392         assertEquals(-1, sb.lastIndexOf("a", -1));
1393         assertEquals(0, sb.lastIndexOf("a", 0));
1394         assertEquals(0, sb.lastIndexOf("a", 1));
1395         assertEquals(2, sb.lastIndexOf("a", 2));
1396         assertEquals(2, sb.lastIndexOf("a", 3));
1397         assertEquals(2, sb.lastIndexOf("a", 4));
1398         assertEquals(2, sb.lastIndexOf("a", 5));
1399 
1400         assertEquals(-1, sb.lastIndexOf("abcdef", 3));
1401         assertEquals("abab".lastIndexOf("", 3), sb.lastIndexOf("", 3));
1402         assertEquals("abab".lastIndexOf("", 1), sb.lastIndexOf("", 1));
1403 
1404         // should work like String#lastIndexOf
1405         assertEquals("abab".lastIndexOf("a", 1), sb.lastIndexOf("a", 1));
1406 
1407         assertEquals(0, sb.lastIndexOf("ab", 1));
1408         // should work like String#lastIndexOf
1409         assertEquals("abab".lastIndexOf("ab", 1), sb.lastIndexOf("ab", 1));
1410 
1411         assertEquals(1, sb.lastIndexOf("b", 2));
1412         assertEquals("abab".lastIndexOf("b", 2), sb.lastIndexOf("b", 2));
1413 
1414         assertEquals(1, sb.lastIndexOf("ba", 2));
1415         assertEquals("abab".lastIndexOf("ba", 2), sb.lastIndexOf("ba", 2));
1416 
1417         assertEquals(-1, sb.lastIndexOf("z", 2));
1418 
1419         sb = new TextStringBuilder("xyzabc");
1420         assertEquals(2, sb.lastIndexOf("za", sb.length()));
1421         assertEquals(-1, sb.lastIndexOf("za", 1));
1422 
1423         assertEquals(-1, sb.lastIndexOf((String) null, 2));
1424     }
1425 
1426     @Test
1427     void testLastIndexOf_StringMatcher() {
1428         final TextStringBuilder sb = new TextStringBuilder();
1429         assertEquals(-1, sb.lastIndexOf((StringMatcher) null));
1430         assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('a')));
1431 
1432         sb.append("ab bd");
1433         assertEquals(0, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('a')));
1434         assertEquals(3, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('b')));
1435         assertEquals(2, sb.lastIndexOf(StringMatcherFactory.INSTANCE.spaceMatcher()));
1436         assertEquals(4, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('d')));
1437         assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.noneMatcher()));
1438         assertEquals(-1, sb.lastIndexOf((StringMatcher) null));
1439 
1440         sb.append(" A1 junction");
1441         assertEquals(6, sb.lastIndexOf(A_NUMBER_MATCHER));
1442     }
1443 
1444     @Test
1445     void testLastIndexOf_StringMatcher_int() {
1446         final TextStringBuilder sb = new TextStringBuilder();
1447         assertEquals(-1, sb.lastIndexOf((StringMatcher) null, 2));
1448         assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), 2));
1449         assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), 0));
1450         assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), -1));
1451 
1452         sb.append("ab bd");
1453         assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), -2));
1454         assertEquals(0, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), 0));
1455         assertEquals(0, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), 2));
1456         assertEquals(0, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('a'), 20));
1457 
1458         assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), -1));
1459         assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 0));
1460         assertEquals(1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 1));
1461         assertEquals(1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 2));
1462         assertEquals(3, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 3));
1463         assertEquals(3, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 4));
1464         assertEquals(3, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 5));
1465         assertEquals(3, sb.lastIndexOf(StringMatcherFactory.INSTANCE.charMatcher('b'), 6));
1466 
1467         assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.spaceMatcher(), -2));
1468         assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.spaceMatcher(), 0));
1469         assertEquals(2, sb.lastIndexOf(StringMatcherFactory.INSTANCE.spaceMatcher(), 2));
1470         assertEquals(2, sb.lastIndexOf(StringMatcherFactory.INSTANCE.spaceMatcher(), 4));
1471         assertEquals(2, sb.lastIndexOf(StringMatcherFactory.INSTANCE.spaceMatcher(), 20));
1472 
1473         assertEquals(-1, sb.lastIndexOf(StringMatcherFactory.INSTANCE.noneMatcher(), 0));
1474         assertEquals(-1, sb.lastIndexOf((StringMatcher) null, 0));
1475 
1476         sb.append(" A1 junction with A2");
1477         assertEquals(-1, sb.lastIndexOf(A_NUMBER_MATCHER, 5));
1478         assertEquals(-1, sb.lastIndexOf(A_NUMBER_MATCHER, 6)); // A matches, 1
1479                                                                // is outside
1480                                                                // bounds
1481         assertEquals(6, sb.lastIndexOf(A_NUMBER_MATCHER, 7));
1482         assertEquals(6, sb.lastIndexOf(A_NUMBER_MATCHER, 22));
1483         assertEquals(6, sb.lastIndexOf(A_NUMBER_MATCHER, 23)); // A matches, 2
1484                                                                // is outside
1485                                                                // bounds
1486         assertEquals(23, sb.lastIndexOf(A_NUMBER_MATCHER, 24));
1487     }
1488 
1489     @Test
1490     void testLeftString() {
1491         final TextStringBuilder sb = new TextStringBuilder("left right");
1492         assertEquals("left", sb.leftString(4));
1493         assertEquals("", sb.leftString(0));
1494         assertEquals("", sb.leftString(-5));
1495         assertEquals("left right", sb.leftString(15));
1496     }
1497 
1498     @Test
1499     void testLength() {
1500         final TextStringBuilder sb = new TextStringBuilder();
1501         assertEquals(0, sb.length());
1502 
1503         sb.append("Hello");
1504         assertEquals(5, sb.length());
1505     }
1506 
1507     @Test
1508     void testMidString() {
1509         final TextStringBuilder sb = new TextStringBuilder("hello goodbye hello");
1510         assertEquals("goodbye", sb.midString(6, 7));
1511         assertEquals("hello", sb.midString(0, 5));
1512         assertEquals("hello", sb.midString(-5, 5));
1513         assertEquals("", sb.midString(0, -1));
1514         assertEquals("", sb.midString(20, 2));
1515         assertEquals("hello", sb.midString(14, 22));
1516     }
1517 
1518     @Test
1519     void testMinimizeCapacity() {
1520         final TextStringBuilder sb = new TextStringBuilder();
1521         sb.minimizeCapacity();
1522         assertEquals(0, sb.capacity());
1523 
1524         sb.append("HelloWorld");
1525         sb.minimizeCapacity();
1526         assertEquals(10, sb.capacity());
1527     }
1528 
1529     @Test
1530     void testOutOfMemoryError() {
1531         // This test is memory hungry requiring at least 7GiB of memory.
1532         // By default expansion will double the buffer size. If we repeat
1533         // add 1GiB of char data then we require at maximum:
1534         // 1GiB char[] data
1535         // 2GiB char[] buffer
1536         // ~4GiB char[] new buffer during reallocation
1537 
1538         // Attempts to guess the amount of free memory available using
1539         // the java.lang.Runtime/java.lang.management objects to
1540         // skip the test often did not work.
1541         // So here we just run the test and return a skip result if the
1542         // OutOfMemoryError occurs too early.
1543 
1544         final TextStringBuilder sb = new TextStringBuilder();
1545         sb.minimizeCapacity();
1546         assertEquals(0, sb.capacity());
1547 
1548         // 1GiB char[] buffer: length is roughly 1/4 the maximum array size
1549         final char[] chars = new char[1 << 29];
1550 
1551         // With infinite memory it should be possible to add this 3 times.
1552         try {
1553             for (int i = 0; i < 3; i++) {
1554                 sb.append(chars);
1555             }
1556         } catch (final OutOfMemoryError ignored) {
1557             Assumptions.abort("Not enough memory for the test");
1558         }
1559 
1560         // Now at 3/4 of the maximum array length.
1561         // Adding is not possible so we expect an OOM error.
1562         assertThrows(OutOfMemoryError.class, () -> sb.append(chars));
1563     }
1564 
1565     @Test
1566     void testOutOfMemoryError2() {
1567         // This test is memory hungry requiring at least 4GiB of memory
1568         // in a single allocation. If not possible then skip the test.
1569 
1570         final TextStringBuilder sb = new TextStringBuilder();
1571         sb.minimizeCapacity();
1572         assertEquals(0, sb.capacity());
1573 
1574         // Allocate a lot
1575         final int small = 10;
1576         final int big = Integer.MAX_VALUE - small;
1577         final char[] extra = new char[small + 1];
1578         try {
1579             sb.ensureCapacity(big);
1580         } catch (final OutOfMemoryError ignored) {
1581             Assumptions.abort("Not enough memory for the test");
1582         }
1583 
1584         fill(sb, big);
1585 
1586         // Adding more than the maximum array size is not possible so we expect an OOM error.
1587         assertThrows(OutOfMemoryError.class, () -> sb.append(extra));
1588     }
1589 
1590     @Test
1591     void testOutOfMemoryError3() {
1592         // This test is memory hungry requiring at least 2GiB of memory
1593         // in a single allocation. If not possible then skip the test.
1594 
1595         final TextStringBuilder sb = new TextStringBuilder();
1596         sb.minimizeCapacity();
1597         assertEquals(0, sb.capacity());
1598 
1599         final int length = 1 << 30;
1600         try {
1601             sb.ensureCapacity(length);
1602         } catch (final OutOfMemoryError ignored) {
1603             Assumptions.abort("Not enough memory for the test");
1604         }
1605 
1606         fill(sb, length);
1607 
1608         // Adding to itself requires a new buffer above the limits of an array
1609         assertThrows(OutOfMemoryError.class, () -> sb.append(sb));
1610     }
1611 
1612     @Test
1613     void testReadFromCharBuffer() throws Exception {
1614         String s = "";
1615         for (int i = 0; i < 100; ++i) {
1616             final TextStringBuilder sb = new TextStringBuilder();
1617             final int len = sb.readFrom(CharBuffer.wrap(s));
1618 
1619             assertEquals(s.length(), len);
1620             assertEquals(s, sb.toString());
1621 
1622             s += Integer.toString(i);
1623         }
1624     }
1625 
1626     @Test
1627     void testReadFromCharBufferAppendsToEnd() throws Exception {
1628         final TextStringBuilder sb = new TextStringBuilder("Test");
1629         sb.readFrom(CharBuffer.wrap(" 123"));
1630         assertEquals("Test 123", sb.toString());
1631     }
1632 
1633     @Test
1634     void testReadFromReadable() throws Exception {
1635         String s = "";
1636         for (int i = 0; i < 100; ++i) {
1637             final TextStringBuilder sb = new TextStringBuilder();
1638             final int len = sb.readFrom(new MockReadable(s));
1639 
1640             assertEquals(s.length(), len);
1641             assertEquals(s, sb.toString());
1642 
1643             s += Integer.toString(i);
1644         }
1645     }
1646 
1647     @Test
1648     void testReadFromReadableAppendsToEnd() throws Exception {
1649         final TextStringBuilder sb = new TextStringBuilder("Test");
1650         sb.readFrom(new MockReadable(" 123"));
1651         assertEquals("Test 123", sb.toString());
1652     }
1653 
1654     @Test
1655     void testReadFromReader() throws Exception {
1656         String s = "1";
1657         for (int i = 0; i < 100; ++i) {
1658             final TextStringBuilder sb = new TextStringBuilder();
1659             final int len = sb.readFrom(new StringReader(s));
1660 
1661             assertEquals(s.length(), len);
1662             assertEquals(s, sb.toString());
1663 
1664             s += Integer.toString(i);
1665         }
1666     }
1667 
1668     @Test
1669     void testReadFromReaderAppendsToEnd() throws Exception {
1670         final TextStringBuilder sb = new TextStringBuilder("Test");
1671         sb.readFrom(new StringReader(" 123"));
1672         assertEquals("Test 123", sb.toString());
1673     }
1674 
1675     @Test
1676     void testReadFromReaderEmpty() throws Exception {
1677         final TextStringBuilder sb = new TextStringBuilder();
1678         final int len = sb.readFrom(new StringReader(StringUtils.EMPTY));
1679         assertEquals(-1, len);
1680         assertEquals(StringUtils.EMPTY, sb.toString());
1681     }
1682 
1683     @Test
1684     void testReadFromReaderInt() throws Exception {
1685         String str = "";
1686         for (int i = 0; i < 100; ++i) {
1687             final TextStringBuilder sb = new TextStringBuilder();
1688             final int len = sb.readFrom(new StringReader(str), str.length());
1689 
1690             assertEquals(str.length(), len);
1691             assertEquals(str, sb.toString());
1692 
1693             str += Integer.toString(i);
1694         }
1695         //
1696         TextStringBuilder sb;
1697         int count;
1698         int target;
1699         final String source = "abc";
1700         final int sourceLen = source.length();
1701         // empty
1702         target = -1;
1703         sb = new TextStringBuilder();
1704         count = sb.readFrom(new StringReader(StringUtils.EMPTY), target);
1705         assertEquals(0, count);
1706         assertEquals(0, sb.size());
1707         assertEquals(source.substring(0, 0), sb.toString());
1708         //
1709         target = -1;
1710         sb = new TextStringBuilder();
1711         count = sb.readFrom(new StringReader(source), target);
1712         assertEquals(0, count);
1713         assertEquals(0, sb.size());
1714         assertEquals(source.substring(0, 0), sb.toString());
1715         //
1716         target = 0;
1717         sb = new TextStringBuilder();
1718         count = sb.readFrom(new StringReader(source), target);
1719         assertEquals(target, count);
1720         assertEquals(target, sb.size());
1721         assertEquals(source.substring(0, target), sb.toString());
1722         //
1723         target = 1;
1724         sb = new TextStringBuilder();
1725         count = sb.readFrom(new StringReader(source), target);
1726         assertEquals(target, count);
1727         assertEquals(target, sb.size());
1728         assertEquals(source.substring(0, target), sb.toString());
1729         //
1730         target = 2;
1731         sb = new TextStringBuilder();
1732         count = sb.readFrom(new StringReader(source), target);
1733         assertEquals(target, count);
1734         assertEquals(target, sb.size());
1735         assertEquals(source.substring(0, target), sb.toString());
1736         //
1737         target = 3;
1738         sb = new TextStringBuilder();
1739         count = sb.readFrom(new StringReader(source), target);
1740         assertEquals(target, count);
1741         assertEquals(target, sb.size());
1742         assertEquals(source.substring(0, target), sb.toString());
1743         //
1744         target = 4;
1745         sb = new TextStringBuilder();
1746         count = sb.readFrom(new StringReader(source), target);
1747         assertEquals(sourceLen, count);
1748         assertEquals(sourceLen, sb.size());
1749         assertEquals(source.substring(0, sourceLen), sb.toString());
1750     }
1751 
1752     @Test
1753     void testReadFromReaderIntEmpty() throws Exception {
1754         final TextStringBuilder sb = new TextStringBuilder();
1755         final int len = sb.readFrom(new StringReader(StringUtils.EMPTY), 1);
1756         assertEquals(-1, len);
1757         assertEquals(StringUtils.EMPTY, sb.toString());
1758     }
1759 
1760     @Test
1761     void testReplace_int_int_String() {
1762         final TextStringBuilder sb = new TextStringBuilder("abc");
1763         sb.replace(0, 1, "d");
1764         assertEquals("dbc", sb.toString());
1765         sb.replace(0, 1, "aaa");
1766         assertEquals("aaabc", sb.toString());
1767         sb.replace(0, 3, "");
1768         assertEquals("bc", sb.toString());
1769         sb.replace(1, 2, (String) null);
1770         assertEquals("b", sb.toString());
1771         sb.replace(1, 1000, "text");
1772         assertEquals("btext", sb.toString());
1773         sb.replace(0, 1000, "text");
1774         assertEquals("text", sb.toString());
1775 
1776         final TextStringBuilder builder = new TextStringBuilder("atext");
1777         builder.replace(1, 1, "ny");
1778         assertEquals("anytext", builder.toString());
1779 
1780         assertThrows(IndexOutOfBoundsException.class, () -> builder.replace(2, 1, "anything"));
1781 
1782         builder.clear();
1783         assertThrows(IndexOutOfBoundsException.class, () -> builder.replace(1, 2, "anything"));
1784         assertThrows(IndexOutOfBoundsException.class, () -> builder.replace(-1, 1, "anything"));
1785     }
1786 
1787     @Test
1788     void testReplace_StringMatcher_String_int_int_int_VaryCount() {
1789         TextStringBuilder sb = new TextStringBuilder("aaxaaaayaa");
1790         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 10, -1);
1791         assertEquals("-x--y-", sb.toString());
1792 
1793         sb = new TextStringBuilder("aaxaaaayaa");
1794         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 10, 0);
1795         assertEquals("aaxaaaayaa", sb.toString());
1796 
1797         sb = new TextStringBuilder("aaxaaaayaa");
1798         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 10, 1);
1799         assertEquals("-xaaaayaa", sb.toString());
1800 
1801         sb = new TextStringBuilder("aaxaaaayaa");
1802         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 10, 2);
1803         assertEquals("-x-aayaa", sb.toString());
1804 
1805         sb = new TextStringBuilder("aaxaaaayaa");
1806         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 10, 3);
1807         assertEquals("-x--yaa", sb.toString());
1808 
1809         sb = new TextStringBuilder("aaxaaaayaa");
1810         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 10, 4);
1811         assertEquals("-x--y-", sb.toString());
1812 
1813         sb = new TextStringBuilder("aaxaaaayaa");
1814         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 10, 5);
1815         assertEquals("-x--y-", sb.toString());
1816     }
1817 
1818     @Test
1819     void testReplace_StringMatcher_String_int_int_int_VaryEndIndex() {
1820         TextStringBuilder sb = new TextStringBuilder("aaxaaaayaa");
1821         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 0, -1);
1822         assertEquals("aaxaaaayaa", sb.toString());
1823 
1824         sb = new TextStringBuilder("aaxaaaayaa");
1825         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 2, -1);
1826         assertEquals("-xaaaayaa", sb.toString());
1827 
1828         sb = new TextStringBuilder("aaxaaaayaa");
1829         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 3, -1);
1830         assertEquals("-xaaaayaa", sb.toString());
1831 
1832         sb = new TextStringBuilder("aaxaaaayaa");
1833         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 4, -1);
1834         assertEquals("-xaaaayaa", sb.toString());
1835 
1836         sb = new TextStringBuilder("aaxaaaayaa");
1837         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 5, -1);
1838         assertEquals("-x-aayaa", sb.toString());
1839 
1840         sb = new TextStringBuilder("aaxaaaayaa");
1841         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 6, -1);
1842         assertEquals("-x-aayaa", sb.toString());
1843 
1844         sb = new TextStringBuilder("aaxaaaayaa");
1845         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 7, -1);
1846         assertEquals("-x--yaa", sb.toString());
1847 
1848         sb = new TextStringBuilder("aaxaaaayaa");
1849         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 8, -1);
1850         assertEquals("-x--yaa", sb.toString());
1851 
1852         sb = new TextStringBuilder("aaxaaaayaa");
1853         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 9, -1);
1854         assertEquals("-x--yaa", sb.toString());
1855 
1856         sb = new TextStringBuilder("aaxaaaayaa");
1857         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 10, -1);
1858         assertEquals("-x--y-", sb.toString());
1859 
1860         sb = new TextStringBuilder("aaxaaaayaa");
1861         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, 1000, -1);
1862         assertEquals("-x--y-", sb.toString());
1863 
1864         final TextStringBuilder builder = new TextStringBuilder("aaxaaaayaa");
1865         assertThrows(IndexOutOfBoundsException.class, () -> builder.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 2, 1, -1));
1866         assertEquals("aaxaaaayaa", builder.toString());
1867     }
1868 
1869     @Test
1870     void testReplace_StringMatcher_String_int_int_int_VaryMatcher() {
1871         TextStringBuilder sb = new TextStringBuilder("abcbccba");
1872         sb.replace((StringMatcher) null, "x", 0, sb.length(), -1);
1873         assertEquals("abcbccba", sb.toString());
1874 
1875         sb.replace(StringMatcherFactory.INSTANCE.charMatcher('a'), "x", 0, sb.length(), -1);
1876         assertEquals("xbcbccbx", sb.toString());
1877 
1878         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("cb"), "x", 0, sb.length(), -1);
1879         assertEquals("xbxcxx", sb.toString());
1880 
1881         sb = new TextStringBuilder("A1-A2A3-A4");
1882         sb.replace(A_NUMBER_MATCHER, "***", 0, sb.length(), -1);
1883         assertEquals("***-******-***", sb.toString());
1884 
1885         sb = new TextStringBuilder();
1886         sb.replace(A_NUMBER_MATCHER, "***", 0, sb.length(), -1);
1887         assertEquals("", sb.toString());
1888     }
1889 
1890     @Test
1891     void testReplace_StringMatcher_String_int_int_int_VaryReplace() {
1892         TextStringBuilder sb = new TextStringBuilder("abcbccba");
1893         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("cb"), "cb", 0, sb.length(), -1);
1894         assertEquals("abcbccba", sb.toString());
1895 
1896         sb = new TextStringBuilder("abcbccba");
1897         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("cb"), "-", 0, sb.length(), -1);
1898         assertEquals("ab-c-a", sb.toString());
1899 
1900         sb = new TextStringBuilder("abcbccba");
1901         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("cb"), "+++", 0, sb.length(), -1);
1902         assertEquals("ab+++c+++a", sb.toString());
1903 
1904         sb = new TextStringBuilder("abcbccba");
1905         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("cb"), "", 0, sb.length(), -1);
1906         assertEquals("abca", sb.toString());
1907 
1908         sb = new TextStringBuilder("abcbccba");
1909         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("cb"), null, 0, sb.length(), -1);
1910         assertEquals("abca", sb.toString());
1911     }
1912 
1913     @Test
1914     void testReplace_StringMatcher_String_int_int_int_VaryStartIndex() {
1915         TextStringBuilder sb = new TextStringBuilder("aaxaaaayaa");
1916         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 0, sb.length(), -1);
1917         assertEquals("-x--y-", sb.toString());
1918 
1919         sb = new TextStringBuilder("aaxaaaayaa");
1920         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 1, sb.length(), -1);
1921         assertEquals("aax--y-", sb.toString());
1922 
1923         sb = new TextStringBuilder("aaxaaaayaa");
1924         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 2, sb.length(), -1);
1925         assertEquals("aax--y-", sb.toString());
1926 
1927         sb = new TextStringBuilder("aaxaaaayaa");
1928         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 3, sb.length(), -1);
1929         assertEquals("aax--y-", sb.toString());
1930 
1931         sb = new TextStringBuilder("aaxaaaayaa");
1932         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 4, sb.length(), -1);
1933         assertEquals("aaxa-ay-", sb.toString());
1934 
1935         sb = new TextStringBuilder("aaxaaaayaa");
1936         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 5, sb.length(), -1);
1937         assertEquals("aaxaa-y-", sb.toString());
1938 
1939         sb = new TextStringBuilder("aaxaaaayaa");
1940         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 6, sb.length(), -1);
1941         assertEquals("aaxaaaay-", sb.toString());
1942 
1943         sb = new TextStringBuilder("aaxaaaayaa");
1944         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 7, sb.length(), -1);
1945         assertEquals("aaxaaaay-", sb.toString());
1946 
1947         sb = new TextStringBuilder("aaxaaaayaa");
1948         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 8, sb.length(), -1);
1949         assertEquals("aaxaaaay-", sb.toString());
1950 
1951         sb = new TextStringBuilder("aaxaaaayaa");
1952         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 9, sb.length(), -1);
1953         assertEquals("aaxaaaayaa", sb.toString());
1954 
1955         sb = new TextStringBuilder("aaxaaaayaa");
1956         sb.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 10, sb.length(), -1);
1957         assertEquals("aaxaaaayaa", sb.toString());
1958 
1959         final TextStringBuilder builder = new TextStringBuilder("aaxaaaayaa");
1960         assertThrows(IndexOutOfBoundsException.class, () -> builder.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", 11, builder.length(), -1));
1961         assertEquals("aaxaaaayaa", builder.toString());
1962 
1963         builder.set("aaxaaaayaa");
1964         assertThrows(IndexOutOfBoundsException.class, () -> builder.replace(StringMatcherFactory.INSTANCE.stringMatcher("aa"), "-", -1, builder.length(), -1));
1965         assertEquals("aaxaaaayaa", builder.toString());
1966     }
1967 
1968     @Test
1969     void testReplaceAll_char_char() {
1970         final TextStringBuilder sb = new TextStringBuilder("abcbccba");
1971         sb.replaceAll('x', 'y');
1972         assertEquals("abcbccba", sb.toString());
1973         sb.replaceAll('a', 'd');
1974         assertEquals("dbcbccbd", sb.toString());
1975         sb.replaceAll('b', 'e');
1976         assertEquals("dececced", sb.toString());
1977         sb.replaceAll('c', 'f');
1978         assertEquals("defeffed", sb.toString());
1979         sb.replaceAll('d', 'd');
1980         assertEquals("defeffed", sb.toString());
1981     }
1982 
1983     @Test
1984     void testReplaceAll_String_String() {
1985         TextStringBuilder sb = new TextStringBuilder("abcbccba");
1986         sb.replaceAll((String) null, null);
1987         assertEquals("abcbccba", sb.toString());
1988         sb.replaceAll((String) null, "anything");
1989         assertEquals("abcbccba", sb.toString());
1990         sb.replaceAll("", null);
1991         assertEquals("abcbccba", sb.toString());
1992         sb.replaceAll("", "anything");
1993         assertEquals("abcbccba", sb.toString());
1994 
1995         sb.replaceAll("x", "y");
1996         assertEquals("abcbccba", sb.toString());
1997         sb.replaceAll("a", "d");
1998         assertEquals("dbcbccbd", sb.toString());
1999         sb.replaceAll("d", null);
2000         assertEquals("bcbccb", sb.toString());
2001         sb.replaceAll("cb", "-");
2002         assertEquals("b-c-", sb.toString());
2003 
2004         sb = new TextStringBuilder("abcba");
2005         sb.replaceAll("b", "xbx");
2006         assertEquals("axbxcxbxa", sb.toString());
2007 
2008         sb = new TextStringBuilder("bb");
2009         sb.replaceAll("b", "xbx");
2010         assertEquals("xbxxbx", sb.toString());
2011     }
2012 
2013     @Test
2014     void testReplaceAll_StringMatcher_String() {
2015         TextStringBuilder sb = new TextStringBuilder("abcbccba");
2016         sb.replaceAll((StringMatcher) null, null);
2017         assertEquals("abcbccba", sb.toString());
2018         sb.replaceAll((StringMatcher) null, "anything");
2019         assertEquals("abcbccba", sb.toString());
2020         sb.replaceAll(StringMatcherFactory.INSTANCE.noneMatcher(), null);
2021         assertEquals("abcbccba", sb.toString());
2022         sb.replaceAll(StringMatcherFactory.INSTANCE.noneMatcher(), "anything");
2023         assertEquals("abcbccba", sb.toString());
2024 
2025         sb.replaceAll(StringMatcherFactory.INSTANCE.charMatcher('x'), "y");
2026         assertEquals("abcbccba", sb.toString());
2027         sb.replaceAll(StringMatcherFactory.INSTANCE.charMatcher('a'), "d");
2028         assertEquals("dbcbccbd", sb.toString());
2029         sb.replaceAll(StringMatcherFactory.INSTANCE.charMatcher('d'), null);
2030         assertEquals("bcbccb", sb.toString());
2031         sb.replaceAll(StringMatcherFactory.INSTANCE.stringMatcher("cb"), "-");
2032         assertEquals("b-c-", sb.toString());
2033 
2034         sb = new TextStringBuilder("abcba");
2035         sb.replaceAll(StringMatcherFactory.INSTANCE.charMatcher('b'), "xbx");
2036         assertEquals("axbxcxbxa", sb.toString());
2037 
2038         sb = new TextStringBuilder("bb");
2039         sb.replaceAll(StringMatcherFactory.INSTANCE.charMatcher('b'), "xbx");
2040         assertEquals("xbxxbx", sb.toString());
2041 
2042         sb = new TextStringBuilder("A1-A2A3-A4");
2043         sb.replaceAll(A_NUMBER_MATCHER, "***");
2044         assertEquals("***-******-***", sb.toString());
2045 
2046         sb = new TextStringBuilder("Dear X, hello X.");
2047         sb.replaceAll(StringMatcherFactory.INSTANCE.stringMatcher("X"), "012345678901234567");
2048         assertEquals("Dear 012345678901234567, hello 012345678901234567.", sb.toString());
2049     }
2050 
2051     @Test
2052     void testReplaceFirst_char_char() {
2053         final TextStringBuilder sb = new TextStringBuilder("abcbccba");
2054         sb.replaceFirst('x', 'y');
2055         assertEquals("abcbccba", sb.toString());
2056         sb.replaceFirst('a', 'd');
2057         assertEquals("dbcbccba", sb.toString());
2058         sb.replaceFirst('b', 'e');
2059         assertEquals("decbccba", sb.toString());
2060         sb.replaceFirst('c', 'f');
2061         assertEquals("defbccba", sb.toString());
2062         sb.replaceFirst('d', 'd');
2063         assertEquals("defbccba", sb.toString());
2064     }
2065 
2066     @Test
2067     void testReplaceFirst_String_String() {
2068         TextStringBuilder sb = new TextStringBuilder("abcbccba");
2069         sb.replaceFirst((String) null, null);
2070         assertEquals("abcbccba", sb.toString());
2071         sb.replaceFirst((String) null, "anything");
2072         assertEquals("abcbccba", sb.toString());
2073         sb.replaceFirst("", null);
2074         assertEquals("abcbccba", sb.toString());
2075         sb.replaceFirst("", "anything");
2076         assertEquals("abcbccba", sb.toString());
2077 
2078         sb.replaceFirst("x", "y");
2079         assertEquals("abcbccba", sb.toString());
2080         sb.replaceFirst("a", "d");
2081         assertEquals("dbcbccba", sb.toString());
2082         sb.replaceFirst("d", null);
2083         assertEquals("bcbccba", sb.toString());
2084         sb.replaceFirst("cb", "-");
2085         assertEquals("b-ccba", sb.toString());
2086 
2087         sb = new TextStringBuilder("abcba");
2088         sb.replaceFirst("b", "xbx");
2089         assertEquals("axbxcba", sb.toString());
2090 
2091         sb = new TextStringBuilder("bb");
2092         sb.replaceFirst("b", "xbx");
2093         assertEquals("xbxb", sb.toString());
2094     }
2095 
2096     @Test
2097     void testReplaceFirst_StringMatcher_String() {
2098         TextStringBuilder sb = new TextStringBuilder("abcbccba");
2099         sb.replaceFirst((StringMatcher) null, null);
2100         assertEquals("abcbccba", sb.toString());
2101         sb.replaceFirst((StringMatcher) null, "anything");
2102         assertEquals("abcbccba", sb.toString());
2103         sb.replaceFirst(StringMatcherFactory.INSTANCE.noneMatcher(), null);
2104         assertEquals("abcbccba", sb.toString());
2105         sb.replaceFirst(StringMatcherFactory.INSTANCE.noneMatcher(), "anything");
2106         assertEquals("abcbccba", sb.toString());
2107 
2108         sb.replaceFirst(StringMatcherFactory.INSTANCE.charMatcher('x'), "y");
2109         assertEquals("abcbccba", sb.toString());
2110         sb.replaceFirst(StringMatcherFactory.INSTANCE.charMatcher('a'), "d");
2111         assertEquals("dbcbccba", sb.toString());
2112         sb.replaceFirst(StringMatcherFactory.INSTANCE.charMatcher('d'), null);
2113         assertEquals("bcbccba", sb.toString());
2114         sb.replaceFirst(StringMatcherFactory.INSTANCE.stringMatcher("cb"), "-");
2115         assertEquals("b-ccba", sb.toString());
2116 
2117         sb = new TextStringBuilder("abcba");
2118         sb.replaceFirst(StringMatcherFactory.INSTANCE.charMatcher('b'), "xbx");
2119         assertEquals("axbxcba", sb.toString());
2120 
2121         sb = new TextStringBuilder("bb");
2122         sb.replaceFirst(StringMatcherFactory.INSTANCE.charMatcher('b'), "xbx");
2123         assertEquals("xbxb", sb.toString());
2124 
2125         sb = new TextStringBuilder("A1-A2A3-A4");
2126         sb.replaceFirst(A_NUMBER_MATCHER, "***");
2127         assertEquals("***-A2A3-A4", sb.toString());
2128     }
2129 
2130     @Test
2131     void testReverse() {
2132         final TextStringBuilder sb = new TextStringBuilder();
2133         assertEquals("", sb.reverse().toString());
2134 
2135         sb.clear().append(true);
2136         assertEquals("eurt", sb.reverse().toString());
2137         assertEquals("true", sb.reverse().toString());
2138     }
2139 
2140     @Test
2141     void testRightString() {
2142         final TextStringBuilder sb = new TextStringBuilder("left right");
2143         assertEquals("right", sb.rightString(5));
2144         assertEquals("", sb.rightString(0));
2145         assertEquals("", sb.rightString(-5));
2146         assertEquals("left right", sb.rightString(15));
2147     }
2148 
2149     @Test
2150     void testSetCharAt() {
2151         final TextStringBuilder sb = new TextStringBuilder();
2152         assertThrows(IndexOutOfBoundsException.class, () -> sb.setCharAt(0, 'f'));
2153         assertThrows(IndexOutOfBoundsException.class, () -> sb.setCharAt(-1, 'f'));
2154         sb.append("foo");
2155         sb.setCharAt(0, 'b');
2156         sb.setCharAt(1, 'a');
2157         sb.setCharAt(2, 'r');
2158         assertThrows(IndexOutOfBoundsException.class, () -> sb.setCharAt(3, '!'));
2159         assertEquals("bar", sb.toString());
2160     }
2161 
2162     @Test
2163     void testSetLength() {
2164         final TextStringBuilder sb = new TextStringBuilder();
2165         sb.append("Hello");
2166         sb.setLength(2); // shorten
2167         assertEquals("He", sb.toString());
2168         sb.setLength(2); // no change
2169         assertEquals("He", sb.toString());
2170         sb.setLength(3); // lengthen
2171         assertEquals("He\0", sb.toString());
2172 
2173         assertThrows(IndexOutOfBoundsException.class, () -> sb.setLength(-1));
2174     }
2175 
2176     @Test
2177     void testSize() {
2178         final TextStringBuilder sb = new TextStringBuilder();
2179         assertEquals(0, sb.size());
2180 
2181         sb.append("Hello");
2182         assertEquals(5, sb.size());
2183     }
2184 
2185     @Test
2186     void testStartsWith() {
2187         final TextStringBuilder sb = new TextStringBuilder();
2188         assertFalse(sb.startsWith("a"));
2189         assertFalse(sb.startsWith(null));
2190         assertTrue(sb.startsWith(""));
2191         sb.append("abc");
2192         assertTrue(sb.startsWith("a"));
2193         assertTrue(sb.startsWith("ab"));
2194         assertTrue(sb.startsWith("abc"));
2195         assertFalse(sb.startsWith("cba"));
2196     }
2197 
2198     @Test
2199     void testSubSequenceIntInt() {
2200         final TextStringBuilder sb = new TextStringBuilder("hello goodbye");
2201         // Start index is negative
2202         assertThrows(IndexOutOfBoundsException.class, () -> sb.subSequence(-1, 5));
2203 
2204         // End index is negative
2205         assertThrows(IndexOutOfBoundsException.class, () -> sb.subSequence(2, -1));
2206 
2207         // End index greater than length()
2208         assertThrows(IndexOutOfBoundsException.class, () -> sb.subSequence(2, sb.length() + 1));
2209 
2210         // Start index greater than end index
2211         assertThrows(IndexOutOfBoundsException.class, () -> sb.subSequence(3, 2));
2212 
2213         // Normal cases
2214         assertEquals("hello", sb.subSequence(0, 5));
2215         assertEquals("hello goodbye".subSequence(0, 6), sb.subSequence(0, 6));
2216         assertEquals("goodbye", sb.subSequence(6, 13));
2217         assertEquals("hello goodbye".subSequence(6, 13), sb.subSequence(6, 13));
2218     }
2219 
2220     @Test
2221     void testSubstringInt() {
2222         final TextStringBuilder sb = new TextStringBuilder("hello goodbye");
2223         assertEquals("goodbye", sb.substring(6));
2224         assertEquals("hello goodbye".substring(6), sb.substring(6));
2225         assertEquals("hello goodbye", sb.substring(0));
2226         assertEquals("hello goodbye".substring(0), sb.substring(0));
2227         assertThrows(IndexOutOfBoundsException.class, () -> sb.substring(-1));
2228 
2229         assertThrows(IndexOutOfBoundsException.class, () -> sb.substring(15));
2230 
2231     }
2232 
2233     @Test
2234     void testSubstringIntInt() {
2235         final TextStringBuilder sb = new TextStringBuilder("hello goodbye");
2236         assertEquals("hello", sb.substring(0, 5));
2237         assertEquals("hello goodbye".substring(0, 6), sb.substring(0, 6));
2238 
2239         assertEquals("goodbye", sb.substring(6, 13));
2240         assertEquals("hello goodbye".substring(6, 13), sb.substring(6, 13));
2241 
2242         assertEquals("goodbye", sb.substring(6, 20));
2243 
2244         assertThrows(IndexOutOfBoundsException.class, () -> sb.substring(-1, 5));
2245 
2246         assertThrows(IndexOutOfBoundsException.class, () -> sb.substring(15, 20));
2247     }
2248 
2249     @Test
2250     void testToCharArray() {
2251         final TextStringBuilder sb = new TextStringBuilder();
2252         assertEquals(0, sb.toCharArray().length);
2253 
2254         char[] a = sb.toCharArray();
2255         assertNotNull(a, "toCharArray() result is null");
2256         assertEquals(0, a.length, "toCharArray() result is too large");
2257 
2258         sb.append("junit");
2259         a = sb.toCharArray();
2260         assertEquals(5, a.length, "toCharArray() result incorrect length");
2261         assertArrayEquals("junit".toCharArray(), a, "toCharArray() result does not match");
2262     }
2263 
2264     @Test
2265     void testToCharArrayIntInt() {
2266         final TextStringBuilder sb = new TextStringBuilder();
2267         assertEquals(0, sb.toCharArray(0, 0).length);
2268 
2269         sb.append("junit");
2270         char[] a = sb.toCharArray(0, 20); // too large test
2271         assertEquals(5, a.length, "toCharArray(int,int) result incorrect length");
2272         assertArrayEquals("junit".toCharArray(), a, "toCharArray(int,int) result does not match");
2273 
2274         a = sb.toCharArray(0, 4);
2275         assertEquals(4, a.length, "toCharArray(int,int) result incorrect length");
2276         assertArrayEquals("juni".toCharArray(), a, "toCharArray(int,int) result does not match");
2277 
2278         a = sb.toCharArray(0, 4);
2279         assertEquals(4, a.length, "toCharArray(int,int) result incorrect length");
2280         assertArrayEquals("juni".toCharArray(), a, "toCharArray(int,int) result does not match");
2281 
2282         a = sb.toCharArray(0, 1);
2283         assertNotNull(a, "toCharArray(int,int) result is null");
2284 
2285         assertThrows(IndexOutOfBoundsException.class, () -> sb.toCharArray(-1, 5));
2286 
2287         assertThrows(IndexOutOfBoundsException.class, () -> sb.toCharArray(6, 5));
2288     }
2289 
2290     @Test
2291     void testToString() {
2292         final TextStringBuilder sb = new TextStringBuilder("abc");
2293         assertEquals("abc", sb.toString());
2294     }
2295 
2296     @Test
2297     void testToStringBuffer() {
2298         final TextStringBuilder sb = new TextStringBuilder();
2299         assertEquals(new StringBuffer().toString(), sb.toStringBuffer().toString());
2300 
2301         sb.append("junit");
2302         assertEquals(new StringBuffer("junit").toString(), sb.toStringBuffer().toString());
2303     }
2304 
2305     @Test
2306     void testToStringBuilder() {
2307         final TextStringBuilder sb = new TextStringBuilder();
2308         assertEquals(new StringBuilder().toString(), sb.toStringBuilder().toString());
2309 
2310         sb.append("junit");
2311         assertEquals(new StringBuilder("junit").toString(), sb.toStringBuilder().toString());
2312     }
2313 
2314     @Test
2315     void testTrim() {
2316         final TextStringBuilder sb = new TextStringBuilder();
2317         assertEquals("", sb.reverse().toString());
2318 
2319         sb.set(" \u0000 ");
2320         assertEquals("", sb.trim().toString());
2321 
2322         sb.set(" \u0000 a b c");
2323         assertEquals("a b c", sb.trim().toString());
2324 
2325         sb.set("a b c \u0000 ");
2326         assertEquals("a b c", sb.trim().toString());
2327 
2328         sb.set(" \u0000 a b c \u0000 ");
2329         assertEquals("a b c", sb.trim().toString());
2330 
2331         sb.set("a b c");
2332         assertEquals("a b c", sb.trim().toString());
2333     }
2334 
2335     @Test
2336     void testWrap_CharArray() {
2337         assertThrows(NullPointerException.class, () -> TextStringBuilder.wrap(null));
2338         //
2339         final TextStringBuilder initEmpty = TextStringBuilder.wrap(ArrayUtils.EMPTY_CHAR_ARRAY);
2340         assertEquals(0, initEmpty.size());
2341         assertEquals(0, initEmpty.length());
2342         initEmpty.append('a');
2343         assertEquals(1, initEmpty.size());
2344         assertEquals(1, initEmpty.length());
2345         //
2346         final char[] test = "abc".toCharArray();
2347         final TextStringBuilder builder = TextStringBuilder.wrap(test);
2348         assertArrayEquals(test, builder.getBuffer());
2349         assertEquals(test.length, builder.length());
2350         assertEquals(test.length, builder.size());
2351         assertFalse(builder.isReallocated());
2352         builder.ensureCapacity(builder.capacity() * 2);
2353         assertFalse(Arrays.equals(test, builder.getBuffer()));
2354         assertTrue(builder.isReallocated());
2355     }
2356 
2357     private void testWrap_CharArray_Int(final String test, final int expectedLen) {
2358         final char[] input = "abc".toCharArray();
2359         final TextStringBuilder builder = TextStringBuilder.wrap(input, expectedLen);
2360         assertArrayEquals(input, builder.getBuffer());
2361         assertEquals(expectedLen, builder.length());
2362         assertEquals(expectedLen, builder.size());
2363         assertFalse(builder.isReallocated());
2364         builder.ensureCapacity(builder.capacity() * 2);
2365         assertFalse(Arrays.equals(input, builder.getBuffer()));
2366         assertTrue(builder.isReallocated());
2367     }
2368 
2369     @Test
2370     void testWrap_CharArray_Int_0() {
2371         testWrap_CharArray_Int("abc", 0);
2372     }
2373 
2374     @Test
2375     void testWrap_CharArray_Int_1() {
2376         testWrap_CharArray_Int("abc", 1);
2377     }
2378 
2379     @Test
2380     void testWrap_CharArray_Int_2() {
2381         testWrap_CharArray_Int("abc", 2);
2382     }
2383 
2384     @Test
2385     void testWrap_CharArray_Int_3() {
2386         testWrap_CharArray_Int("abc", 3);
2387     }
2388 
2389     @Test
2390     void testWrap_CharArray_Int_Empty_0() {
2391         final TextStringBuilder initEmpty = TextStringBuilder.wrap(ArrayUtils.EMPTY_CHAR_ARRAY, 0);
2392         assertEquals(0, initEmpty.size());
2393         assertEquals(0, initEmpty.length());
2394         initEmpty.append('a');
2395         assertEquals(1, initEmpty.size());
2396         assertEquals(1, initEmpty.length());
2397     }
2398 
2399     @Test
2400     void testWrap_CharArray_Int_Exceptions() {
2401         assertThrows(NullPointerException.class, () -> TextStringBuilder.wrap(null, 0));
2402         assertThrows(IllegalArgumentException.class, () -> TextStringBuilder.wrap("abc".toCharArray(), -1));
2403         assertThrows(IllegalArgumentException.class, () -> TextStringBuilder.wrap(ArrayUtils.EMPTY_CHAR_ARRAY, 1));
2404     }
2405 }