1/*
2 *  RopeTest.java
3 *  Copyright (C) 2007 Amin Ahmad.
4 *
5 *  This file is part of Java Ropes.
6 *
7 *  Java Ropes is free software: you can redistribute it and/or modify
8 *  it under the terms of the GNU General Public License as published by
9 *  the Free Software Foundation, either version 3 of the License, or
10 *  (at your option) any later version.
11 *
12 *  Java Ropes is distributed in the hope that it will be useful,
13 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 *  GNU General Public License for more details.
16 *
17 *  You should have received a copy of the GNU General Public License
18 *  along with Java Ropes.  If not, see <http://www.gnu.org/licenses/>.
19 *
20 *  Amin Ahmad can be contacted at amin.ahmad@gmail.com or on the web at
21 *  www.ahmadsoft.org.
22 */
23package org.ahmadsoft.ropes.test;
24
25import java.io.ByteArrayInputStream;
26import java.io.ByteArrayOutputStream;
27import java.io.IOException;
28import java.io.ObjectInputStream;
29import java.io.ObjectOutputStream;
30import java.io.StringWriter;
31import java.io.Writer;
32import java.util.Iterator;
33import java.util.regex.Pattern;
34
35import junit.framework.Assert;
36import junit.framework.TestCase;
37
38import org.ahmadsoft.ropes.Rope;
39import org.ahmadsoft.ropes.impl.ConcatenationRope;
40import org.ahmadsoft.ropes.impl.FlatCharSequenceRope;
41import org.ahmadsoft.ropes.impl.ReverseRope;
42import org.ahmadsoft.ropes.impl.SubstringRope;
43
44public class RopeTest extends TestCase {
45
46	private String fromRope(Rope rope, int start, int end) {
47		try {
48			Writer out = new StringWriter(end - start);
49			rope.write(out, start, end - start);
50			return out.toString();
51		} catch (IOException ex) {
52			ex.printStackTrace();
53			return null;
54		}
55	}
56	public void testSubstringDeleteBug() {
57		   String s = "12345678902234567890";
58
59		   Rope rope = Rope.BUILDER.build(s.toCharArray()); // bugs
60
61		   rope = rope.delete(0, 1);
62		   assertEquals("23", fromRope(rope, 0, 2));
63		   assertEquals("", fromRope(rope, 0, 0));
64		   assertEquals("902", fromRope(rope, 7, 10));
65
66
67		   rope = Rope.BUILDER.build(s); // no bugs
68		   rope = rope.delete(0, 1);
69		   assertEquals("23", fromRope(rope, 0, 2));
70		   assertEquals("", fromRope(rope, 0, 0));
71		   assertEquals("902", fromRope(rope, 7, 10));
72		}
73
74	/**
75	 * Bug reported by ugg.ugg@gmail.com.
76	 */
77	public void testRopeWriteBug() {
78		Rope r = Rope.BUILDER.build("");
79		r = r.append("round ");
80		r = r.append(Integer.toString(0));
81		r = r.append(" 1234567890");
82
83		assertEquals("round ", fromRope(r,0,6));
84		assertEquals("round 0", fromRope(r,0,7));
85		assertEquals("round 0 ", fromRope(r,0,8));
86		assertEquals("round 0 1", fromRope(r,0,9));
87		assertEquals("round 0 12", fromRope(r,0,10));
88		assertEquals("round 0 1234567890", fromRope(r,0,18));
89		assertEquals("round 0 1234567890", fromRope(r,0,r.length()));
90	}
91
92
93	public void testTemp() {
94		// insert temporary code here.
95	}
96
97	public void testLengthOverflow() {
98		Rope x1 = Rope.BUILDER.build("01");
99		for (int j=2;j<31;++j)
100			x1 = x1.append(x1);
101		assertEquals(1073741824, x1.length());
102		try {
103			x1 = x1.append(x1);
104			fail("Expected overflow.");
105		} catch (IllegalArgumentException e) {
106			// this is what we expect
107		}
108	}
109
110	public void testMatches() {
111		Rope x1 = new FlatCharSequenceRope("0123456789");
112		Rope x2 = new ConcatenationRope(x1, x1);
113
114		assertTrue(x2.matches("0.*9"));
115		assertTrue(x2.matches(Pattern.compile("0.*9")));
116
117		assertTrue(x2.matches("0.*90.*9"));
118		assertTrue(x2.matches(Pattern.compile("0.*90.*9")));
119	}
120
121	public void testConcatenationFlatFlat() {
122		Rope r1 = Rope.BUILDER.build("alpha");
123		final Rope r2 = Rope.BUILDER.build("beta");
124		Rope r3 = r1.append(r2);
125		Assert.assertEquals("alphabeta", r3.toString());
126
127		r1 = Rope.BUILDER.build("The quick brown fox jumped over");
128		r3 = r1.append(r1);
129		Assert.assertEquals("The quick brown fox jumped overThe quick brown fox jumped over", r3.toString());
130	}
131
132	public void testIterator() {
133		Rope x1 = new FlatCharSequenceRope("0123456789");
134		Rope x2 = new FlatCharSequenceRope("0123456789");
135		Rope x3 = new FlatCharSequenceRope("0123456789");
136		ConcatenationRope c1 = new ConcatenationRope(x1, x2);
137		ConcatenationRope c2 = new ConcatenationRope(c1, x3);
138
139		Iterator<Character> i = c2.iterator();
140		for (int j = 0; j < c2.length(); ++j) {
141			assertTrue("Has next (" + j + "/" + c2.length() + ")", i.hasNext());
142			i.next();
143		}
144		assertTrue(!i.hasNext());
145
146		FlatCharSequenceRope z1 = new FlatCharSequenceRope("0123456789");
147		Rope z2 = new SubstringRope(z1, 2, 0);
148		Rope z3 = new SubstringRope(z1, 2, 2);
149		Rope z4 = new ConcatenationRope(z3, new SubstringRope(z1, 6, 2)); // 2367
150
151		i = z2.iterator();
152		assertTrue(!i.hasNext());
153		i = z3.iterator();
154		assertTrue(i.hasNext());
155		assertEquals((char) '2',(char) i.next());
156		assertTrue(i.hasNext());
157		assertEquals((char) '3', (char) i.next());
158		assertTrue(!i.hasNext());
159		for (int j=0; j<=z3.length(); ++j) {
160			try {
161				z3.iterator(j);
162			} catch (Exception e) {
163				fail(j + " " + e.toString());
164			}
165		}
166		assertTrue(4 == z4.length());
167		for (int j=0; j<=z4.length(); ++j) {
168			try {
169				z4.iterator(j);
170			} catch (Exception e) {
171				fail(j + " " + e.toString());
172			}
173		}
174		i=z4.iterator(4);
175		assertTrue(!i.hasNext());
176		i=z4.iterator(2);
177		assertTrue(i.hasNext());
178		assertEquals((char) '6',(char) i.next());
179		assertTrue(i.hasNext());
180		assertEquals((char) '7',(char) i.next());
181		assertTrue(!i.hasNext());
182
183
184	}
185
186	public void testReverse() {
187		Rope x1 = new FlatCharSequenceRope("012345");
188		Rope x2 = new FlatCharSequenceRope("67");
189		Rope x3 = new ConcatenationRope(x1, x2);
190
191		assertEquals("543210", x1.reverse().toString());
192		assertEquals("76543210", x3.reverse().toString());
193		assertEquals(x3.reverse(), x3.reverse().reverse().reverse());
194		assertEquals("654321", x3.reverse().subSequence(1, 7).toString());
195	}
196
197
198	public void testTrim() {
199		Rope x1 = new FlatCharSequenceRope("\u0012  012345");
200		Rope x2 = new FlatCharSequenceRope("\u0002 67	       \u0007");
201		Rope x3 = new ConcatenationRope(x1, x2);
202
203		assertEquals("012345", x1.trimStart().toString());
204		assertEquals("67	       \u0007", x2.trimStart().toString());
205		assertEquals("012345\u0002 67	       \u0007", x3.trimStart().toString());
206
207		assertEquals("\u0012  012345", x1.trimEnd().toString());
208		assertEquals("\u0002 67", x2.trimEnd().toString());
209		assertEquals("\u0012  012345\u0002 67", x3.trimEnd().toString());
210		assertEquals("012345\u0002 67", x3.trimEnd().reverse().trimEnd().reverse().toString());
211
212		assertEquals(x3.trimStart().trimEnd(), x3.trimEnd().trimStart());
213		assertEquals(x3.trimStart().trimEnd(), x3.trimStart().reverse().trimStart().reverse());
214		assertEquals(x3.trimStart().trimEnd(), x3.trim());
215	}
216
217	public void testCreation() {
218		try {
219			Rope.BUILDER.build("The quick brown fox jumped over");
220		} catch (final Exception e) {
221			Assert.fail("Nonempty string: " + e.getMessage());
222		}
223		try {
224			Rope.BUILDER.build("");
225		} catch (final Exception e) {
226			Assert.fail("Empty string: " + e.getMessage());
227		}
228	}
229
230	public void testEquals() {
231		final Rope r1 = Rope.BUILDER.build("alpha");
232		final Rope r2 = Rope.BUILDER.build("beta");
233		final Rope r3 = Rope.BUILDER.build("alpha");
234
235		Assert.assertEquals(r1, r3);
236		Assert.assertFalse(r1.equals(r2));
237	}
238
239	public void testHashCode() {
240		final Rope r1 = Rope.BUILDER.build("alpha");
241		final Rope r2 = Rope.BUILDER.build("beta");
242		final Rope r3 = Rope.BUILDER.build("alpha");
243
244		Assert.assertEquals(r1.hashCode(), r3.hashCode());
245		Assert.assertFalse(r1.hashCode() == r2.hashCode());
246	}
247
248	public void testHashCode2() {
249		Rope r1 = new FlatCharSequenceRope(new StringBuffer("The quick brown fox."));
250		Rope r2 = new ConcatenationRope(new FlatCharSequenceRope(""), new FlatCharSequenceRope("The quick brown fox."));
251
252		assertTrue(r1.equals(r2));
253		assertTrue(r1.equals(r2));
254	}
255
256	public void testIndexOf() {
257		final Rope r1 = Rope.BUILDER.build("alpha");
258		final Rope r2 = Rope.BUILDER.build("beta");
259		final Rope r3 = r1.append(r2);
260		Assert.assertEquals(1, r3.indexOf('l'));
261		Assert.assertEquals(6, r3.indexOf('e'));
262
263
264		Rope r = Rope.BUILDER.build("abcdef");
265		assertEquals(-1, r.indexOf('z'));
266		assertEquals(0, r.indexOf('a'));
267		assertEquals(1, r.indexOf('b'));
268		assertEquals(5, r.indexOf('f'));
269
270
271		assertEquals(1, r.indexOf('b', 0));
272		assertEquals(0, r.indexOf('a', 0));
273		assertEquals(-1, r.indexOf('z', 0));
274		assertEquals(-1, r.indexOf('b',2));
275		assertEquals(5, r.indexOf('f',5));
276
277		assertEquals(2, r.indexOf("cd", 1));
278
279		r = Rope.BUILDER.build("The quick brown fox jumped over the jumpy brown dog.");
280		assertEquals(0, r.indexOf("The"));
281		assertEquals(10, r.indexOf("brown"));
282		assertEquals(10, r.indexOf("brown", 10));
283		assertEquals(42, r.indexOf("brown",11));
284		assertEquals(-1, r.indexOf("brown",43));
285		assertEquals(-1, r.indexOf("hhe"));
286
287		r = Rope.BUILDER.build("zbbzzz");
288		assertEquals(-1, r.indexOf("ab",1));
289	}
290
291	public void testInsert() {
292		final Rope r1 = Rope.BUILDER.build("alpha");
293		Assert.assertEquals("betaalpha", r1.insert(0, "beta").toString());
294		Assert.assertEquals("alphabeta", r1.insert(r1.length(), "beta").toString());
295		Assert.assertEquals("abetalpha", r1.insert(1, "beta").toString());
296	}
297
298	public void testPrepend() {
299		Rope r1 = Rope.BUILDER.build("alphabeta");
300		for (int j=0;j<2;++j)
301			r1 = r1.subSequence(0, 5).append(r1);
302		Assert.assertEquals("alphaalphaalphabeta", r1.toString());
303		r1 = r1.append(r1.subSequence(5, 15));
304		Assert.assertEquals("alphaalphaalphabetaalphaalpha", r1.toString());
305	}
306
307	public void testCompareTo() {
308		final Rope r1 = Rope.BUILDER.build("alpha");
309		final Rope r2 = Rope.BUILDER.build("beta");
310		final Rope r3 = Rope.BUILDER.build("alpha");
311		final Rope r4 = Rope.BUILDER.build("alpha1");
312		final String s2 = "beta";
313
314		assertTrue(r1.compareTo(r3) == 0);
315		assertTrue(r1.compareTo(r2) < 0);
316		assertTrue(r2.compareTo(r1) > 0);
317		assertTrue(r1.compareTo(r4) < 0);
318		assertTrue(r4.compareTo(r1) > 0);
319		assertTrue(r1.compareTo(s2) < 0);
320		assertTrue(r2.compareTo(s2) == 0);
321	}
322
323	public void testToString() {
324		String phrase = "The quick brown fox jumped over the lazy brown dog. Boy am I glad the dog was asleep.";
325		final Rope r1 = Rope.BUILDER.build(phrase);
326		assertTrue(phrase.equals(r1.toString()));
327		assertTrue(phrase.subSequence(7, 27).equals(r1.subSequence(7, 27).toString()));
328	}
329
330	public void testReverseIterator() {
331		FlatCharSequenceRope r1 = new FlatCharSequenceRope("01234");
332		ReverseRope r2 = new ReverseRope(r1);
333		SubstringRope r3 = new SubstringRope(r1, 0, 3);
334		ConcatenationRope r4 = new ConcatenationRope(new ConcatenationRope(r1,r2),r3);	//0123443210012
335
336		Iterator<Character> x = r1.reverseIterator();
337		assertTrue(x.hasNext());
338		assertEquals((char) '4',(char)  x.next());
339		assertTrue(x.hasNext());
340		assertEquals((char) '3',(char)  x.next());
341		assertTrue(x.hasNext());
342		assertEquals((char) '2',(char)  x.next());
343		assertTrue(x.hasNext());
344		assertEquals((char) '1',(char)  x.next());
345		assertTrue(x.hasNext());
346		assertEquals((char) '0',(char)  x.next());
347		assertFalse(x.hasNext());
348
349		x = r1.reverseIterator(4);
350		assertTrue(x.hasNext());
351		assertEquals((char) '0',(char)  x.next());
352		assertFalse(x.hasNext());
353
354		x = r2.reverseIterator();
355		assertTrue(x.hasNext());
356		assertEquals((char) '0',(char)  x.next());
357		assertTrue(x.hasNext());
358		assertEquals((char) '1',(char)  x.next());
359		assertTrue(x.hasNext());
360		assertEquals((char) '2',(char)  x.next());
361		assertTrue(x.hasNext());
362		assertEquals((char) '3',(char)  x.next());
363		assertTrue(x.hasNext());
364		assertEquals((char) '4',(char)  x.next());
365		assertFalse(x.hasNext());
366
367		x = r2.reverseIterator(4);
368		assertTrue(x.hasNext());
369		assertEquals((char) '4',(char)  x.next());
370		assertFalse(x.hasNext());
371
372		x = r3.reverseIterator();
373		assertTrue(x.hasNext());
374		assertEquals((char) '2',(char)  x.next());
375		assertTrue(x.hasNext());
376		assertEquals((char) '1',(char)  x.next());
377		assertTrue(x.hasNext());
378		assertEquals((char) '0',(char)  x.next());
379		assertFalse(x.hasNext());
380
381		x = r3.reverseIterator(1);
382		assertTrue(x.hasNext());
383		assertEquals((char) '1',(char)  x.next());
384		assertTrue(x.hasNext());
385		assertEquals((char) '0',(char)  x.next());
386		assertFalse(x.hasNext());
387
388		x = r4.reverseIterator(); //0123443210012
389		assertTrue(x.hasNext());
390		assertEquals((char) '2',(char)  x.next());
391		assertTrue(x.hasNext());
392		assertEquals((char) '1',(char)  x.next());
393		assertTrue(x.hasNext());
394		assertEquals((char) '0',(char)  x.next());
395		assertTrue(x.hasNext());
396		assertEquals((char) '0',(char)  x.next());
397		assertTrue(x.hasNext());
398		assertEquals((char) '1',(char)  x.next());
399		assertTrue(x.hasNext());
400		assertEquals((char) '2',(char)  x.next());
401		assertTrue(x.hasNext());
402		assertEquals((char) '3',(char)  x.next());
403		assertTrue(x.hasNext());
404		assertEquals((char) '4',(char)  x.next());
405		assertTrue(x.hasNext());
406		assertEquals((char) '4',(char)  x.next());
407		assertTrue(x.hasNext());
408		assertEquals((char) '3',(char)  x.next());
409		assertTrue(x.hasNext());
410		assertEquals((char) '2',(char)  x.next());
411		assertTrue(x.hasNext());
412		assertEquals((char) '1',(char)  x.next());
413		assertTrue(x.hasNext());
414		assertEquals((char) '0',(char)  x.next());
415		assertFalse(x.hasNext());
416
417		x = r4.reverseIterator(7);
418		assertEquals((char) '4',(char)  x.next());
419		assertTrue(x.hasNext());
420		assertEquals((char) '4',(char)  x.next());
421		assertTrue(x.hasNext());
422		assertEquals((char) '3',(char)  x.next());
423		assertTrue(x.hasNext());
424		assertEquals((char) '2',(char)  x.next());
425		assertTrue(x.hasNext());
426		assertEquals((char) '1',(char)  x.next());
427		assertTrue(x.hasNext());
428		assertEquals((char) '0',(char)  x.next());
429		assertFalse(x.hasNext());
430
431		x = r4.reverseIterator(12);
432		assertTrue(x.hasNext());
433		assertEquals((char) '0',(char)  x.next());
434		assertFalse(x.hasNext());
435
436		x = r4.reverseIterator(13);
437		assertFalse(x.hasNext());
438
439	}
440
441	public void testSerialize() {
442		FlatCharSequenceRope r1 = new FlatCharSequenceRope("01234");
443		ReverseRope r2 = new ReverseRope(r1);
444		SubstringRope r3 = new SubstringRope(r1, 0, 1);
445		ConcatenationRope r4 = new ConcatenationRope(new ConcatenationRope(r1,r2),r3);	//01234432100
446
447		ByteArrayOutputStream out = new ByteArrayOutputStream();
448		try {
449			ObjectOutputStream oos = new ObjectOutputStream(out);
450			oos.writeObject(r4);
451			oos.close();
452			ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
453			ObjectInputStream ois = new ObjectInputStream(in);
454			Rope r = (Rope) ois.readObject();
455			assertTrue(r instanceof FlatCharSequenceRope);
456		} catch (Exception e) {
457			fail(e.toString());
458		}
459
460
461	}
462
463	public void testPadStart() {
464		Rope r = Rope.BUILDER.build("hello");
465		assertEquals("hello", r.padStart(5).toString());
466		assertEquals("hello", r.padStart(0).toString());
467		assertEquals("hello", r.padStart(-1).toString());
468		assertEquals(" hello", r.padStart(6).toString());
469		assertEquals("  hello", r.padStart(7).toString());
470		assertEquals("~hello", r.padStart(6, '~').toString());
471		assertEquals("~~hello", r.padStart(7, '~').toString());
472		assertEquals("~~~~~~~~~~~~~~~~~~~~~~~~~hello", r.padStart(30, '~').toString());
473	}
474
475	public void testPadEnd() {
476		Rope r = Rope.BUILDER.build("hello");
477		assertEquals("hello", r.padEnd(5).toString());
478		assertEquals("hello", r.padEnd(0).toString());
479		assertEquals("hello", r.padEnd(-1).toString());
480		assertEquals("hello ", r.padEnd(6).toString());
481		assertEquals("hello  ", r.padEnd(7).toString());
482		assertEquals("hello~", r.padEnd(6, '~').toString());
483		assertEquals("hello~~", r.padEnd(7, '~').toString());
484		assertEquals("hello~~~~~~~~~~~~~~~~~~~~~~~~~", r.padEnd(30, '~').toString());
485	}
486
487	public void testSubstringBounds() {
488		Rope r  = Rope.BUILDER.build("01234567890123456789012345678901234567890123456789012345678901234567890123456789".toCharArray());
489		Rope r2 = r.subSequence(0, 30);
490		try{
491			r2.charAt(31);
492			fail("Expected IndexOutOfBoundsException");
493		} catch (IndexOutOfBoundsException e) {
494			// success
495		}
496	}
497
498	public void testAppend() {
499		Rope r = Rope.BUILDER.build("");
500		r=r.append('a');
501		assertEquals("a", r.toString());
502		r=r.append("boy");
503		assertEquals("aboy", r.toString());
504		r=r.append("test", 0, 4);
505		assertEquals("aboytest", r.toString());
506	}
507
508	public void testEmpty() {
509		Rope r1 = Rope.BUILDER.build("");
510		Rope r2 = Rope.BUILDER.build("012345");
511
512		assertTrue(r1.isEmpty());
513		assertFalse(r2.isEmpty());
514		assertTrue(r2.subSequence(2, 2).isEmpty());
515	}
516	public void testCharAt() {
517		FlatCharSequenceRope r1 = new FlatCharSequenceRope("0123456789");
518		SubstringRope r2 = new SubstringRope(r1,0,1);
519		SubstringRope r3 = new SubstringRope(r1,9,1);
520		ConcatenationRope r4 = new ConcatenationRope(r1, r3);
521
522		assertEquals('0', r1.charAt(0));
523		assertEquals('9', r1.charAt(9));
524		assertEquals('0', r2.charAt(0));
525		assertEquals('9', r3.charAt(0));
526		assertEquals('0', r4.charAt(0));
527		assertEquals('9', r4.charAt(9));
528		assertEquals('9', r4.charAt(10));
529	}
530
531	public void testRegexp() {
532		ConcatenationRope r = new ConcatenationRope(new FlatCharSequenceRope("012345"), new FlatCharSequenceRope("6789"));
533		CharSequence c = r.getForSequentialAccess();
534		for (int j=0; j<10; ++j) {
535			assertEquals(r.charAt(j), c.charAt(j));
536		}
537		c = r.getForSequentialAccess();
538
539		int[] indices={1,2,1,3,5,0,6,7,8,1,7,7,7};
540		for (int i: indices) {
541			assertEquals("Index: " + i, r.charAt(i), c.charAt(i));
542		}
543	}
544
545	public void testStartsEndsWith() {
546		final Rope r = Rope.BUILDER.build("Hello sir, how do you do?");
547		assertTrue(r.startsWith(""));
548		assertTrue(r.startsWith("H"));
549		assertTrue(r.startsWith("He"));
550		assertTrue(r.startsWith("Hello "));
551		assertTrue(r.startsWith("", 0));
552		assertTrue(r.startsWith("H", 0));
553		assertTrue(r.startsWith("He", 0));
554		assertTrue(r.startsWith("Hello ", 0));
555		assertTrue(r.startsWith("", 1));
556		assertTrue(r.startsWith("e", 1));
557		assertTrue(r.endsWith("?"));
558		assertTrue(r.endsWith("do?"));
559		assertTrue(r.endsWith("o", 1));
560		assertTrue(r.endsWith("you do", 1));
561	}
562
563	/**
564	 * Reported by Blake Watkins <blakewatkins@gmail.com> on
565	 * 21 Mar 2009.
566	 */
567	public void testIndexOfBug() {
568		{   // original test, bwatkins
569			String s1 = "CCCCCCPIFPCFFP";
570			String s2 = "IFPCFFP";
571
572			Rope r1 = Rope.BUILDER.build(s1);
573			Assert.assertEquals(s1.indexOf(s2), r1.indexOf(s2));
574		}
575		{   // extra test, aahmad
576			String s1 = "ABABAABBABABBAAABBBAAABABABABBBBAA";
577			String s2 = "ABABAB";
578
579			Rope r1 = Rope.BUILDER.build(s1);
580			Assert.assertEquals(s1.indexOf(s2), r1.indexOf(s2));
581		}
582	}
583}
584