001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Alexey A. Ivanov
019: * @version $Revision$
020: */package javax.swing.text;
021:
022: import java.lang.ref.Reference;
023: import java.lang.ref.ReferenceQueue;
024: import java.lang.ref.WeakReference;
025: import java.util.Vector;
026: import javax.swing.undo.UndoableEdit;
027: import junit.framework.TestCase;
028:
029: public class GapContent_ComplexUndoTest extends TestCase {
030: protected AbstractDocument.Content content;
031:
032: @Override
033: protected void setUp() throws Exception {
034: content = new GapContent();
035: }
036:
037: /**
038: * Insert some characters, undo all insertions and then redo them.
039: * We should get the same string.
040: *
041: * @throws BadLocationException
042: */
043: public void testUndoRedo1() throws BadLocationException {
044: char[] chars = { '0', '1', '2', '3', '4' };
045: UndoableEdit[] undo = new UndoableEdit[chars.length];
046: int i;
047: for (i = 0; i < 5; i++) {
048: undo[i] = content.insertString(i, new String(chars, i, 1));
049: }
050: // Now undo till the end
051: for (i = undo.length - 1; i >= 0; i--) {
052: undo[i].undo();
053: }
054: // Then redo
055: for (i = 0; i < undo.length; i++) {
056: undo[i].redo();
057: }
058: // This should give us the same result
059: assertEquals("01234", content
060: .getString(0, content.length() - 1));
061: }
062:
063: /**
064: * Add some characters, insert several in the middle, undo all actions,
065: * redo all actions. The content should be the same.
066: *
067: * @throws BadLocationException
068: */
069: public void testUndoRedo2() throws BadLocationException {
070: char[] chars = { '0', '1', '2', '3', '4', 'a', 'b', 'c' };
071: UndoableEdit[] undo = new UndoableEdit[chars.length];
072: int i;
073: for (i = 0; i < 5; i++) {
074: undo[i] = content.insertString(i, new String(chars, i, 1));
075: }
076: for (; i < chars.length; i++) {
077: undo[i] = content.insertString(i - 2, new String(chars, i,
078: 1));
079: }
080: // Now undo till the end
081: for (i = undo.length - 1; i >= 3; i--) {
082: undo[i].undo();
083: }
084: // Then redo
085: for (++i; i < undo.length; i++) {
086: undo[i].redo();
087: }
088: // This should give us the same result
089: assertEquals("012abc34", content.getString(0,
090: content.length() - 1));
091: }
092:
093: /**
094: * Insert character into the content causing the buffer to grow.
095: *
096: * @throws BadLocationException
097: */
098: public void testUndoRedo3() throws BadLocationException {
099: content.insertString(0, "012345678");
100: char[] chars = { '9', '0', '1', 'a', 'b', 'c' };
101: UndoableEdit[] undo = new UndoableEdit[chars.length];
102: int i;
103: for (i = 0; i < 3; i++) {
104: undo[i] = content.insertString(content.length() - 1,
105: new String(chars, i, 1));
106: }
107: for (; i < chars.length; i++) {
108: undo[i] = content.insertString(i, new String(chars, i, 1));
109: }
110: // Now undo till the end
111: for (i = undo.length - 1; i >= 3; i--) {
112: undo[i].undo();
113: }
114: // Then redo
115: for (++i; i < undo.length; i++) {
116: undo[i].redo();
117: }
118: // This should give us the same result
119: assertEquals("012abc345678901", content.getString(0, content
120: .length() - 1));
121: }
122:
123: /**
124: * Creates positions at specified offsets and stores them in array.
125: *
126: * @param offsets array of offsets where positions are to be created
127: * @param positions array of positions to store to
128: * @throws BadLocationException
129: */
130: private void addPositions(final int[] offsets,
131: final Position[] positions) throws BadLocationException {
132: for (int i = 0; i < offsets.length; i++) {
133: positions[i] = content.createPosition(offsets[i]);
134: }
135: }
136:
137: /**
138: * Checks that positions have the expected offsets.
139: *
140: * @param offsets expected offsets
141: * @param positions position array to be checked
142: */
143: private void checkPositions(final int[] offsets,
144: final Position[] positions) {
145: for (int i = 0; i < offsets.length; i++) {
146: assertEquals(offsets[i], positions[i].getOffset());
147: }
148: }
149:
150: /**
151: * Make sure the positions get updated correctly while using
152: * undo and redo.
153: *
154: * @throws BadLocationException
155: */
156: public void testUndoRedo4() throws BadLocationException {
157: content.insertString(0, "yuiop\n123456\n789987\nabcdef");
158: // 012345 6789012 3456789 012345
159: int[] off1 = { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24 };
160: Position[] pos1 = new Position[off1.length];
161: addPositions(off1, pos1);
162: UndoableEdit[] undo = new UndoableEdit[3];
163: // Remove the second line from the text
164: undo[0] = content.remove(6, 7);
165: assertEquals("yuiop\n789987\nabcdef\n", content.getString(0,
166: content.length()));
167: assertEquals("p\n", content.getString(pos1[2].getOffset(),
168: pos1[6].getOffset() - pos1[2].getOffset()));
169: // Remove the second line from the text (it was the third one)
170: undo[1] = content.remove(6, 7);
171: assertEquals("yuiop\nabcdef\n", content.getString(0, content
172: .length()));
173: assertEquals("p\n", content.getString(pos1[2].getOffset(),
174: pos1[6].getOffset() - pos1[2].getOffset()));
175: // Insert a string at the same position (in the beginning
176: // of the second line)
177: undo[2] = content.insertString(6, "qwerty");
178: assertEquals("yuiop\nqwertyabcdef\n", content.getString(0,
179: content.length()));
180: // Add more positions
181: int[] off2 = { 6, 7, 8, 9, 10 };
182: Position[] pos2 = new Position[off2.length];
183: int[] off2Del = { 6, 6, 6, 6, 6 };
184: addPositions(off2, pos2);
185: assertEquals("p\nqwer", content.getString(pos1[2].getOffset(),
186: pos2[4].getOffset() - pos1[2].getOffset()));
187: // Now undo twice
188: // Undo the first time
189: undo[2].undo();
190: // Check the positions we added the second time, and
191: // the text between two positions
192: checkPositions(off2Del, pos2);
193: assertEquals("", content.getString(pos1[4].getOffset(), pos2[1]
194: .getOffset()
195: - pos1[4].getOffset()));
196: // Undo the second time
197: undo[1].undo();
198: assertEquals("789987\n", content.getString(pos1[4].getOffset(),
199: pos2[1].getOffset() - pos1[4].getOffset()));
200: // And redo once
201: undo[1].redo();
202: // Check positions and text in the buffer
203: checkPositions(off2Del, pos2);
204: assertEquals("yuiop\nabcdef\n", content.getString(0, content
205: .length()));
206: // This assertion was failing, throwing the exception as
207: // pos1[4] was negative :-), but of course shouldn't
208: assertEquals("", content.getString(pos1[4].getOffset(), pos2[1]
209: .getOffset()
210: - pos1[4].getOffset()));
211: }
212:
213: /**
214: * Undo after some positions have been garbage collected.
215: *
216: * @throws BadLocationException
217: */
218: public void testUndoGC() throws BadLocationException {
219: content.insertString(0, "012345678");
220: Vector<WeakReference<Position>> pos = new Vector<WeakReference<Position>>(
221: 10);
222: ReferenceQueue<Position> rq = new ReferenceQueue<Position>();
223: for (int i = 0; i < content.length(); i += 2) {
224: pos.add(new WeakReference<Position>(content
225: .createPosition(i), rq));
226: }
227: int count = 0;
228: int i;
229: for (i = 0; i < 100; i++) {
230: System.gc();
231: Reference<?> r;
232: if ((r = rq.poll()) != null) {
233: pos.remove(r);
234: count++;
235: if (pos.size() == 0) {
236: break;
237: }
238: }
239: }
240: // This call causes all the garbage collected positions to be
241: // removed from the internal list
242: UndoableEdit ue = content.remove(0, 5);
243: assertEquals("5678", content.getString(0, content.length() - 1));
244: // Test (it shouldn't fail with any NullPointerException)
245: ue.undo();
246: assertEquals("012345678", content.getString(0,
247: content.length() - 1));
248: }
249: }
|