View | Details | Raw Unified | Return to bug 89599 | Differences between
and this patch

Collapse All | Expand All

(-)src/org/eclipse/jface/text/tests/JFaceTextTestSuite.java (+1 lines)
Lines 29-34 Link Here
29
		suite.addTest(TextHoverPopupTest.suite());
29
		suite.addTest(TextHoverPopupTest.suite());
30
		suite.addTest(TextPresentationTest.suite());
30
		suite.addTest(TextPresentationTest.suite());
31
		suite.addTest(TextUtilitiesTest.suite());
31
		suite.addTest(TextUtilitiesTest.suite());
32
		suite.addTest(SharedUndoManagerTest.suite());
32
		suite.addTest(UndoManagerTest.suite());
33
		suite.addTest(UndoManagerTest.suite());
33
		
34
		
34
		suite.addTest(RulesTestSuite.suite());
35
		suite.addTest(RulesTestSuite.suite());
(-)src/org/eclipse/jface/text/tests/SharedUndoManagerTest.java (+484 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2005 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.jface.text.tests;
12
13
import junit.framework.Test;
14
import junit.framework.TestCase;
15
import junit.framework.TestSuite;
16
17
import org.eclipse.swt.SWT;
18
import org.eclipse.swt.widgets.Shell;
19
20
import org.eclipse.jface.text.BadLocationException;
21
import org.eclipse.jface.text.SharedDocumentUndoManager;
22
import org.eclipse.jface.text.Document;
23
import org.eclipse.jface.text.IDocument;
24
import org.eclipse.jface.text.ITextViewer;
25
import org.eclipse.jface.text.IUndoManager;
26
import org.eclipse.jface.text.Position;
27
import org.eclipse.jface.text.TextViewer;
28
29
/**
30
 * Test for SharedDocumentUndoManager
31
 */
32
public class SharedUndoManagerTest extends TestCase {
33
34
	/** The maximum undo level. */
35
	private static final int MAX_UNDO_LEVEL= 256;
36
	
37
	/** The shell. */
38
	private Shell fShell;
39
	/** The text viewer. */
40
	private ITextViewer fTextViewer;
41
	/** The undo manager. */
42
	private IUndoManager fUndoManager;
43
44
	private static final int LOOP_COUNT= 20;
45
	
46
	//--- Static data sets for comparing scenarios - obtained from capturing random data ---
47
	/** Original document */
48
	private static final String INITIAL_DOCUMENT_CONTENT= "+7cyg:/F!T4KnW;0+au$t1G%(`Z|u'7'_!-k?<c\"2Y.]CwsO.r";
49
	/** Replacement string */
50
	private static final String [] REPLACEMENTS= { ">", "F", "M/r-*", "-", "bl", "", "}%/#", "", "k&", "f", "\\g", "c!x", "TLG-", "NPO", "Rp9u", "", "X", "W(", ")z", "oe", "", "h*", "t", "I", "X=N>", "2yt", "&Z", "2)W=", ":K", "P9S", "s8t8o", "", "", "5{7", "%", "", "v3", "Wz", "sH", "3c", "8", "ol", ",6$", "94[#", ".~", "n", ">", "9", "W", ",(FW", "Q", "^", "Bq", "$", "re", "", "9", "8[", "Mx", "4b", "$6", "F", "8s]", "o", "-", "E&6", "S\\", "/", "z.a", "4ai", "b", ")", "", "l", "VU", "7M+Ql", "xZ?x", "xx", "lc", "b", "A", "!", "4pSU", "", "{J", "H", "l>_", "n&9", "", "&`", ";igQxq", "", ">", ";\"", "k\\`]G", "o{?", "", "K", "_6", "="};
51
	/** Position/offset pairs */
52
	private static final int [] POSITIONS= { 18, 2, 43, 1, 3, 2, 28, 3, 35, 1, 23, 5, 32, 2, 30, 1, 22, 1, 37, 0, 23, 3, 43, 2, 46, 1, 17, 1, 36, 6, 17, 5, 30, 4, 25, 1, 2, 2, 30, 0, 37, 3, 28, 1, 30, 2, 20, 5, 33, 1, 29, 1, 15, 2, 21, 2, 24, 4, 38, 3, 8, 0, 33, 2, 15, 2, 25, 0, 8, 2, 20, 3, 43, 2, 44, 1, 44, 2, 32, 2, 40, 2, 32, 3, 12, 2, 38, 3, 33, 2, 46, 0, 13, 3, 45, 0, 16, 2, 3, 2, 44, 0, 48, 0, 18, 5, 7, 6, 7, 3, 40, 0, 9, 1, 16, 3, 28, 3, 36, 1, 35, 2, 0, 3, 6, 1, 10, 4, 14, 2, 15, 3, 33, 1, 36, 0, 37, 0, 4, 3, 31, 3, 33, 3, 11, 3, 20, 2, 25, 3, 4, 3, 7, 3, 17, 0, 3, 1, 31, 3, 34, 1, 21, 0, 33, 1, 17, 4, 9, 1, 26, 3, 2, 3, 12, 1, 26, 3, 9, 5, 5, 0, 31, 3, 0, 3, 12, 1, 1, 1, 3, 0, 39, 0, 9, 2, 2, 0, 28, 2};
53
54
	private static final boolean DEBUG= false;
55
56
	public static Test suite() {
57
		return new TestSuite(SharedUndoManagerTest.class);
58
	}
59
	
60
	/*
61
	 * @see TestCase#TestCase(String)
62
	 */
63
	public SharedUndoManagerTest(final String name) {
64
		super(name);	
65
	}
66
	
67
	/*
68
	 *  @see TestCase#setUp()
69
	 */
70
	protected void setUp() {
71
		fShell= new Shell();	
72
		fUndoManager= new SharedDocumentUndoManager(MAX_UNDO_LEVEL);
73
		fTextViewer= new TextViewer(fShell, SWT.NONE);
74
		fTextViewer.setUndoManager(fUndoManager);
75
		fUndoManager.connect(fTextViewer);
76
	}
77
	
78
	/*
79
	 *  @see TestCase#tearDown()
80
	 */
81
	protected void tearDown() {
82
		fUndoManager.disconnect();
83
	}
84
85
	/**
86
	 * Test for line delimiter conversion.
87
	 */	
88
	public void testConvertLineDelimiters() {
89
		final String original= "a\r\nb\r\n";
90
		final IDocument document= new Document(original);		
91
		fTextViewer.setDocument(document);
92
		
93
		try {
94
			document.replace(1, 2, "\n");
95
			document.replace(3, 2, "\n");
96
		} catch (BadLocationException e) {
97
			assertTrue(false);
98
		}
99
		
100
		assertTrue(fUndoManager.undoable());
101
		fUndoManager.undo();
102
		assertTrue(fUndoManager.undoable());
103
		fUndoManager.undo();
104
105
		final String reverted= document.get();
106
		
107
		assertEquals(original, reverted);
108
	}
109
110
	/**
111
	 * Randomly applies document changes.
112
	 */
113
	public void testRandomAccess() {
114
		final int RANDOM_STRING_LENGTH= 50;
115
		final int RANDOM_REPLACE_COUNT= 100;
116
		
117
		assertTrue(RANDOM_REPLACE_COUNT >= 1);
118
		assertTrue(RANDOM_REPLACE_COUNT <= MAX_UNDO_LEVEL);
119
		
120
		String original= createRandomString(RANDOM_STRING_LENGTH);
121
		final IDocument document= new Document(original);
122
		fTextViewer.setDocument(document);
123
	
124
		doChange(document, RANDOM_REPLACE_COUNT);
125
		
126
		assertTrue(fUndoManager.undoable());
127
		while (fUndoManager.undoable())
128
			fUndoManager.undo();
129
			
130
		final String reverted= document.get();
131
		assertEquals(original, reverted);
132
	}
133
	
134
	private void doChange(IDocument document, int count) {
135
		try {
136
			String before = document.get();
137
			
138
			if (DEBUG)
139
				System.out.println(before);
140
			
141
			Position [] positions = new Position[count];
142
			String [] strings = new String[count];
143
			for (int i= 0; i < count; i++) {
144
				final Position position= createRandomPositionPoisson(document.getLength());
145
				final String string= createRandomStringPoisson(4);
146
				document.replace(position.getOffset(), position.getLength(), string);
147
				positions[i]= position;
148
				strings[i]= string;
149
			}
150
			
151
			if (DEBUG) {
152
				System.out.print("{ ");
153
				for (int i=0; i<count; i++) {
154
					System.out.print(positions[i].getOffset());
155
					System.out.print(", ");
156
					System.out.print(positions[i].getLength());
157
					System.out.print(", ");
158
				}
159
				System.out.println(" }");
160
				System.out.print("{ ");
161
				for (int i=0; i<count; i++) {
162
					System.out.print("\"");
163
					System.out.print(strings[i]);
164
					System.out.print("\", ");
165
				}
166
				System.out.println(" }");
167
			}
168
		} catch (BadLocationException e) {
169
			assertTrue(false);
170
		}
171
	}
172
	
173
	// repeatable test case for comparing success/failure among different tests
174
	private void doRepeatableChange(IDocument document) {
175
		assertTrue(POSITIONS.length >= (2 * REPLACEMENTS.length));
176
		try {
177
			for (int i= 0; i < REPLACEMENTS.length; i++) {
178
				int offset= POSITIONS[i*2];
179
				int length= POSITIONS[i*2+1];
180
				if (document.getLength() > offset + length)
181
					document.replace(offset, length, REPLACEMENTS[i]);
182
				else
183
					document.replace(0,0, REPLACEMENTS[i]);
184
			}
185
		} catch (BadLocationException e) {
186
			assertTrue(false);
187
		}
188
	}
189
	
190
	public void testLoopRandomAccessAsCompound() {
191
		int i= 0;
192
		while (i < LOOP_COUNT) {
193
			fUndoManager.reset();
194
			testRandomAccessAsCompound();
195
			i++;
196
		}
197
	}
198
	
199
	public void testLoopRandomAccess() {
200
		int i= 0;
201
		while (i < LOOP_COUNT) {
202
			fUndoManager.reset();
203
			testRandomAccess();
204
			i++;
205
		}
206
	}
207
	
208
	public void testLoopRandomAccessAsUnclosedCompound() {
209
		int i= 0;
210
		while (i < LOOP_COUNT) {
211
			fUndoManager.reset();
212
			testRandomAccessAsUnclosedCompound();
213
			i++;
214
		}
215
	}
216
	
217
	public void testLoopConvertLineDelimiters() {
218
		int i= 0;
219
		while (i < LOOP_COUNT) {
220
			fUndoManager.reset();
221
			testConvertLineDelimiters();
222
			i++;
223
		}
224
	}
225
	
226
	public void testLoopRandomAccessWithMixedCompound() {
227
		int i= 0;
228
		while (i < LOOP_COUNT) {
229
			fUndoManager.reset();
230
			testRandomAccessWithMixedCompound();
231
			i++;
232
		}
233
	}
234
	
235
	public void testRandomAccessAsCompound() {
236
		final int RANDOM_STRING_LENGTH= 50;
237
		final int RANDOM_REPLACE_COUNT= 100;
238
		
239
		assertTrue(RANDOM_REPLACE_COUNT >= 1);
240
		assertTrue(RANDOM_REPLACE_COUNT <= MAX_UNDO_LEVEL);
241
		
242
		String original= createRandomString(RANDOM_STRING_LENGTH);
243
		final IDocument document= new Document(original);
244
		fTextViewer.setDocument(document);
245
246
		fUndoManager.beginCompoundChange();		
247
		doChange(document, RANDOM_REPLACE_COUNT);
248
		fUndoManager.endCompoundChange();
249
250
		assertTrue(fUndoManager.undoable());
251
		while (fUndoManager.undoable())
252
			fUndoManager.undo();
253
		assertTrue(!fUndoManager.undoable());
254
			
255
		final String reverted= document.get();
256
257
		assertEquals(original, reverted);		
258
	}
259
	
260
	/**
261
	 * Test case for https://bugs.eclipse.org/bugs/show_bug.cgi?id=88172
262
	 */
263
	public void testRandomAccessAsUnclosedCompound() {
264
		
265
		final int RANDOM_STRING_LENGTH= 50;
266
		final int RANDOM_REPLACE_COUNT= 100;
267
		
268
		assertTrue(RANDOM_REPLACE_COUNT >= 1);
269
		assertTrue(RANDOM_REPLACE_COUNT <= MAX_UNDO_LEVEL);
270
		
271
		String original= createRandomString(RANDOM_STRING_LENGTH);
272
		final IDocument document= new Document(original);
273
		fTextViewer.setDocument(document);
274
275
		fUndoManager.beginCompoundChange();		
276
		doChange(document, RANDOM_REPLACE_COUNT);
277
		// do not close the compound.
278
		// fUndoManager.endCompoundChange();
279
280
		assertTrue(fUndoManager.undoable());
281
		while (fUndoManager.undoable())
282
			fUndoManager.undo();
283
		assertTrue(!fUndoManager.undoable());
284
			
285
		final String reverted= document.get();
286
287
		assertEquals(original, reverted);		
288
	}
289
	
290
	public void testRandomAccessWithMixedCompound() {
291
292
		final int RANDOM_STRING_LENGTH= 50;
293
		final int RANDOM_REPLACE_COUNT= 10;
294
		final int NUMBER_COMPOUNDS= 5;
295
		final int NUMBER_ATOMIC_PER_COMPOUND= 3;
296
		
297
		assertTrue(RANDOM_REPLACE_COUNT >= 1);
298
		assertTrue(NUMBER_COMPOUNDS * (1 + NUMBER_ATOMIC_PER_COMPOUND) * RANDOM_REPLACE_COUNT <= MAX_UNDO_LEVEL);
299
		
300
		String original= createRandomString(RANDOM_STRING_LENGTH);
301
		final IDocument document= new Document(original);
302
		fTextViewer.setDocument(document);
303
304
		for (int i= 0; i < NUMBER_COMPOUNDS; i++) {
305
			fUndoManager.beginCompoundChange();		
306
			doChange(document, RANDOM_REPLACE_COUNT);
307
			fUndoManager.endCompoundChange();
308
			assertTrue(fUndoManager.undoable());
309
			for (int j= 0; j < NUMBER_ATOMIC_PER_COMPOUND; j++) {
310
				doChange(document, RANDOM_REPLACE_COUNT);
311
				assertTrue(fUndoManager.undoable());
312
			}
313
		}
314
315
		assertTrue(fUndoManager.undoable());
316
		while (fUndoManager.undoable())
317
			fUndoManager.undo();
318
		assertTrue(!fUndoManager.undoable());
319
			
320
		final String reverted= document.get();
321
322
		assertEquals(original, reverted);		
323
	}
324
325
	public void testRepeatableAccess() {
326
		assertTrue(REPLACEMENTS.length <= MAX_UNDO_LEVEL);
327
		
328
		final IDocument document= new Document(INITIAL_DOCUMENT_CONTENT);
329
		fTextViewer.setDocument(document);
330
	
331
		doRepeatableChange(document);
332
		
333
		assertTrue(fUndoManager.undoable());
334
		while (fUndoManager.undoable())
335
			fUndoManager.undo();
336
			
337
		final String reverted= document.get();
338
339
		assertEquals(INITIAL_DOCUMENT_CONTENT, reverted);
340
	}
341
	
342
	public void testRepeatableAccessAsCompound() {
343
		assertTrue(REPLACEMENTS.length <= MAX_UNDO_LEVEL);
344
345
		final IDocument document= new Document(INITIAL_DOCUMENT_CONTENT);
346
		fTextViewer.setDocument(document);
347
	
348
		fUndoManager.beginCompoundChange();
349
		doRepeatableChange(document);
350
		fUndoManager.endCompoundChange();
351
		
352
		assertTrue(fUndoManager.undoable());
353
		fUndoManager.undo();
354
		// with a single compound, there should be only one undo
355
		assertFalse(fUndoManager.undoable());
356
			
357
		final String reverted= document.get();
358
359
		assertEquals(INITIAL_DOCUMENT_CONTENT, reverted);
360
	}
361
	
362
	public void testRepeatableAccessAsUnclosedCompound() {
363
		assertTrue(REPLACEMENTS.length <= MAX_UNDO_LEVEL);
364
		
365
		final IDocument document= new Document(INITIAL_DOCUMENT_CONTENT);
366
		fTextViewer.setDocument(document);
367
	
368
		fUndoManager.beginCompoundChange();
369
		doRepeatableChange(document);
370
		
371
		assertTrue(fUndoManager.undoable());
372
		while (fUndoManager.undoable())
373
			fUndoManager.undo();
374
			
375
		final String reverted= document.get();
376
377
		assertEquals(INITIAL_DOCUMENT_CONTENT, reverted);
378
	}
379
	
380
	public void testRepeatableAccessWithMixedAndEmptyCompound() {
381
		assertTrue(REPLACEMENTS.length + 2 <= MAX_UNDO_LEVEL);
382
383
		final IDocument document= new Document(INITIAL_DOCUMENT_CONTENT);
384
		fTextViewer.setDocument(document);
385
386
		fUndoManager.beginCompoundChange();		
387
		doRepeatableChange(document);
388
		fUndoManager.endCompoundChange();
389
		assertTrue(fUndoManager.undoable());
390
		
391
		// insert an empty compound
392
		fUndoManager.beginCompoundChange();
393
		fUndoManager.endCompoundChange();
394
			
395
	    // insert the atomic changes
396
		doRepeatableChange(document);
397
398
		assertTrue(fUndoManager.undoable());
399
		while (fUndoManager.undoable())
400
			fUndoManager.undo();
401
		assertTrue(!fUndoManager.undoable());
402
			
403
		final String reverted= document.get();
404
405
		assertEquals(INITIAL_DOCUMENT_CONTENT, reverted);		
406
	}
407
	
408
	public void testDocumentStamp() {
409
		final Document document= new Document(INITIAL_DOCUMENT_CONTENT);
410
		fTextViewer.setDocument(document);
411
		long stamp= document.getModificationStamp();
412
		doChange(document, 1);
413
		fUndoManager.undo();
414
		assertEquals(stamp, document.getModificationStamp());
415
416
	}
417
	
418
	private static String createRandomString(int length) {
419
		final StringBuffer buffer= new StringBuffer();
420
		
421
		for (int i= 0; i < length; i++)
422
			buffer.append(getRandomCharacter());
423
424
		return buffer.toString();
425
	}
426
	
427
	private static final char getRandomCharacter() {
428
//		return Math.random() < 0.5
429
//			? '\r'
430
//			: '\n';
431
					
432
		// XXX must include \r, \n, \t
433
		return (char) (32 + 95 * Math.random());
434
	}
435
	
436
	private static String createRandomStringPoisson(int mean) {
437
		final int length= getRandomPoissonValue(2);
438
		return createRandomString(length);
439
	}
440
	
441
	private static Position createRandomPositionPoisson(int documentLength) {
442
443
		final float random= (float) Math.random();
444
		final int offset= (int) (random * (documentLength + 1));
445
446
		int length= getRandomPoissonValue(2);
447
		if (offset + length > documentLength)
448
			length= documentLength - offset;
449
			
450
		return new Position(offset, length);
451
	}
452
	
453
	private static int getRandomPoissonValue(int mean) {
454
		final int MAX_VALUE= 10;
455
456
		final float random= (float) Math.random();
457
		float probability= 0;
458
		int i= 0;
459
		while (probability < 1 && i < MAX_VALUE) {
460
			probability += getPoissonDistribution(mean, i);
461
			if (random <= probability)
462
				break;
463
			i++;
464
		}		
465
		return i;
466
	}
467
468
	private static float getPoissonDistribution(float lambda, int k) {
469
		return (float) (Math.exp(-lambda) * Math.pow(lambda, k) / faculty(k));
470
	}
471
	
472
	/**
473
	 * Returns the faculty of k.
474
	 * 
475
	 * @param k the <code>int</code> for which to get the faculty
476
	 * @return the faculty
477
	 */
478
	private static final int faculty(int k) {
479
		return k == 0
480
			? 1
481
			: k * faculty(k - 1);
482
	}
483
	
484
}

Return to bug 89599