| /******************************************************************************* |
| * Copyright (c) 2019 Paul Pazderski and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Paul Pazderski - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.debug.tests.console; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Queue; |
| import java.util.Random; |
| import java.util.concurrent.atomic.AtomicInteger; |
| |
| import org.eclipse.core.runtime.ILogListener; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.debug.tests.AbstractDebugTest; |
| import org.eclipse.jface.text.Document; |
| import org.eclipse.jface.text.IDocument; |
| import org.eclipse.jface.text.IDocumentAdapter; |
| import org.eclipse.swt.custom.TextChangeListener; |
| import org.eclipse.swt.custom.TextChangedEvent; |
| import org.eclipse.swt.custom.TextChangingEvent; |
| import org.eclipse.ui.internal.console.ConsoleDocumentAdapter; |
| import org.junit.Test; |
| |
| /** |
| * Tests {@link ConsoleDocumentAdapter}. |
| * <p> |
| * Primary tests fixed width mode and calculation of {@link TextChangingEvent}s. |
| * </p> |
| */ |
| @SuppressWarnings("restriction") |
| public class ConsoleDocumentAdapterTests extends AbstractDebugTest { |
| |
| /** |
| * Test {@link ConsoleDocumentAdapter#setText(String)}. |
| */ |
| @Test |
| public void testSetText() { |
| final ExpectingTextChangeListener eventListener = new ExpectingTextChangeListener(true, null); |
| final IDocumentAdapter docAdapter = new ConsoleDocumentAdapter(-1); |
| docAdapter.setDocument(new Document()); |
| docAdapter.addTextChangeListener(eventListener); |
| |
| final String text = "123456"; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.SET)); |
| docAdapter.setText(text); |
| assertContent(docAdapter, text); |
| assertNumberOfLines(docAdapter, 1); |
| checkLineMapping(docAdapter, null); |
| |
| for (String s : new String[] { "", null }) { |
| docAdapter.setText(s); |
| assertContent(docAdapter, ""); |
| assertNumberOfLines(docAdapter, 1); |
| checkLineMapping(docAdapter, null); |
| } |
| } |
| |
| /** |
| * Test fixed width line wrap. (mostly with changes affecting a single line) |
| */ |
| @Test |
| public void testLineWrap() { |
| final Random rand = new Random(4); |
| final int wrapWidth = 10; |
| final IDocumentAdapter docAdapter = new ConsoleDocumentAdapter(wrapWidth); |
| final ExpectingTextChangeListener eventListener = new ExpectingTextChangeListener(false, docAdapter); |
| assertEquals("Failed to set width.", wrapWidth, ((ConsoleDocumentAdapter) docAdapter).getWidth()); |
| docAdapter.setDocument(new Document()); |
| docAdapter.addTextChangeListener(eventListener); |
| // repeated add should not result in repeated events |
| docAdapter.addTextChangeListener(eventListener); |
| |
| // initialize document |
| final String initText = "012345"; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.SET)); |
| docAdapter.setText(initText); |
| assertNumberOfLines(docAdapter, 1); |
| assertLine(docAdapter, 0, initText); |
| checkLineMapping(docAdapter, rand); |
| |
| // add text without new line wrap |
| String addText = "67"; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, docAdapter.getCharCount(), addText, 0, addText.length(), 0, 0)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, addText); |
| assertNumberOfLines(docAdapter, 1); |
| assertLine(docAdapter, 0, "01234567"); |
| checkLineMapping(docAdapter, rand); |
| |
| // add text with one new line wrap |
| addText = "89AB"; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, docAdapter.getCharCount(), addText, 0, addText.length(), 0, 1)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, addText); |
| assertNumberOfLines(docAdapter, 2); |
| assertLine(docAdapter, 0, "0123456789"); |
| assertLine(docAdapter, 1, "AB"); |
| checkLineMapping(docAdapter, rand); |
| |
| // insert text in wrapped line without new line wrap |
| int offset = 6; |
| addText = "---"; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, addText, 0, addText.length(), 1, 1)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, 0, addText); |
| assertNumberOfLines(docAdapter, 2); |
| assertLine(docAdapter, 0, "012345---6"); |
| assertLine(docAdapter, 1, "789AB"); |
| checkLineMapping(docAdapter, rand); |
| |
| // remove last insert |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, "", 3, 0, 1, 1)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, 3, ""); |
| assertNumberOfLines(docAdapter, 2); |
| assertLine(docAdapter, 0, "0123456789"); |
| assertLine(docAdapter, 1, "AB"); |
| checkLineMapping(docAdapter, rand); |
| |
| // add text with two new line wrap |
| addText = "CDEFGHIJabcdefghijKL"; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, docAdapter.getCharCount(), addText, 0, addText.length(), 0, 2)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, addText); |
| assertNumberOfLines(docAdapter, 4); |
| assertLine(docAdapter, 0, "0123456789"); |
| assertLine(docAdapter, 1, "ABCDEFGHIJ"); |
| assertLine(docAdapter, 2, "abcdefghij"); |
| assertLine(docAdapter, 3, "KL"); |
| checkLineMapping(docAdapter, rand); |
| |
| // replace text without new line wrap |
| String replaceText = "~~~"; |
| offset = 3; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, replaceText, replaceText.length(), replaceText.length(), 0, 0)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, replaceText.length(), replaceText); |
| assertNumberOfLines(docAdapter, 4); |
| assertLine(docAdapter, 0, "012~~~6789"); |
| assertLine(docAdapter, 1, "ABCDEFGHIJ"); |
| assertLine(docAdapter, 2, "abcdefghij"); |
| assertLine(docAdapter, 3, "KL"); |
| checkLineMapping(docAdapter, rand); |
| |
| // remove text with one removed line wrap |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, "", 3, 0, 3, 2)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, 3, ""); |
| assertNumberOfLines(docAdapter, 3); |
| assertLine(docAdapter, 0, "012" + "6789ABC"); |
| assertLine(docAdapter, 1, "DEFGHIJabc"); |
| assertLine(docAdapter, 2, "defghijKL"); |
| checkLineMapping(docAdapter, rand); |
| |
| // insert text with one new line wrap |
| addText = "345"; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, addText, 0, addText.length(), 2, 3)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, 0, addText); |
| assertNumberOfLines(docAdapter, 4); |
| assertLine(docAdapter, 0, "0123456789"); |
| assertLine(docAdapter, 1, "ABCDEFGHIJ"); |
| assertLine(docAdapter, 2, "abcdefghij"); |
| assertLine(docAdapter, 3, "KL"); |
| checkLineMapping(docAdapter, rand); |
| |
| // add text ending at fixed width border |
| addText = "MNOPQRST"; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, docAdapter.getCharCount(), addText, 0, addText.length(), 0, 0)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, addText); |
| assertNumberOfLines(docAdapter, 4); |
| assertLine(docAdapter, 0, "0123456789"); |
| assertLine(docAdapter, 1, "ABCDEFGHIJ"); |
| assertLine(docAdapter, 2, "abcdefghij"); |
| assertLine(docAdapter, 3, "KLMNOPQRST"); |
| assertEquals("Got wrong line index.", 3, docAdapter.getLineAtOffset(40)); |
| checkLineMapping(docAdapter, rand); |
| |
| // add text starting at fixed width border |
| addText = "kl"; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, docAdapter.getCharCount(), addText, 0, addText.length(), 0, 1)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, addText); |
| assertNumberOfLines(docAdapter, 5); |
| assertLine(docAdapter, 0, "0123456789"); |
| assertLine(docAdapter, 1, "ABCDEFGHIJ"); |
| assertLine(docAdapter, 2, "abcdefghij"); |
| assertLine(docAdapter, 3, "KLMNOPQRST"); |
| assertLine(docAdapter, 4, "kl"); |
| checkLineMapping(docAdapter, rand); |
| |
| // insert text starting at fixed width border |
| addText = ">"; |
| offset = docAdapter.getCharCount() - 2; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, addText, 0, addText.length(), 0, 0)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, 0, addText); |
| assertNumberOfLines(docAdapter, 5); |
| assertLine(docAdapter, 0, "0123456789"); |
| assertLine(docAdapter, 1, "ABCDEFGHIJ"); |
| assertLine(docAdapter, 2, "abcdefghij"); |
| assertLine(docAdapter, 3, "KLMNOPQRST"); |
| assertLine(docAdapter, 4, ">kl"); |
| checkLineMapping(docAdapter, rand); |
| |
| // delete character at fixed width border |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, "", 1, 0, 0, 0)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, 1, ""); |
| assertNumberOfLines(docAdapter, 5); |
| assertLine(docAdapter, 0, "0123456789"); |
| assertLine(docAdapter, 1, "ABCDEFGHIJ"); |
| assertLine(docAdapter, 2, "abcdefghij"); |
| assertLine(docAdapter, 3, "KLMNOPQRST"); |
| assertLine(docAdapter, 4, "kl"); |
| checkLineMapping(docAdapter, rand); |
| |
| // add newline to start... new line |
| addText = "\n"; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, docAdapter.getCharCount(), addText, 0, addText.length(), 0, 1)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, addText); |
| assertNumberOfLines(docAdapter, 6); |
| assertLine(docAdapter, 0, "0123456789"); |
| assertLine(docAdapter, 1, "ABCDEFGHIJ"); |
| assertLine(docAdapter, 2, "abcdefghij"); |
| assertLine(docAdapter, 3, "KLMNOPQRST"); |
| assertLine(docAdapter, 4, "kl"); |
| assertLine(docAdapter, 5, ""); |
| assertEquals("Got wrong line.", 4, docAdapter.getLineAtOffset(docAdapter.getCharCount() - 2)); |
| assertEquals("Got wrong line.", 4, docAdapter.getLineAtOffset(docAdapter.getCharCount() - 1)); |
| assertEquals("Got wrong line.", 5, docAdapter.getLineAtOffset(docAdapter.getCharCount())); |
| assertEquals("Get wrong content.", "\n", docAdapter.getTextRange(42, 1)); |
| checkLineMapping(docAdapter, rand); |
| |
| // add text ending at fixed width border |
| addText = "UVWXYZ.,:;"; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, docAdapter.getCharCount(), addText, 0, addText.length(), 0, 0)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, addText); |
| assertNumberOfLines(docAdapter, 6); |
| assertLine(docAdapter, 0, "0123456789"); |
| assertLine(docAdapter, 1, "ABCDEFGHIJ"); |
| assertLine(docAdapter, 2, "abcdefghij"); |
| assertLine(docAdapter, 3, "KLMNOPQRST"); |
| assertLine(docAdapter, 4, "kl"); |
| assertLine(docAdapter, 5, "UVWXYZ.,:;"); |
| assertEquals("Got wrong line.", 5, docAdapter.getLineAtOffset(docAdapter.getCharCount())); |
| assertEquals("Get wrong content.", "l\nU", docAdapter.getTextRange(41, 3)); |
| checkLineMapping(docAdapter, rand); |
| |
| // remove text without line wrap change |
| offset = docAdapter.getOffsetAtLine(docAdapter.getLineCount() - 1) + 2; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, "", 4, 0, 0, 0)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, 4, ""); |
| assertNumberOfLines(docAdapter, 6); |
| assertLine(docAdapter, 0, "0123456789"); |
| assertLine(docAdapter, 1, "ABCDEFGHIJ"); |
| assertLine(docAdapter, 2, "abcdefghij"); |
| assertLine(docAdapter, 3, "KLMNOPQRST"); |
| assertLine(docAdapter, 4, "kl"); |
| assertLine(docAdapter, 5, "UV" + ".,:;"); |
| checkLineMapping(docAdapter, rand); |
| |
| // replace and insert text and end at fixed width border |
| replaceText = "WXYZ.,:;"; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, replaceText, 4, replaceText.length(), 0, 0)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, 4, replaceText); |
| assertNumberOfLines(docAdapter, 6); |
| assertLine(docAdapter, 0, "0123456789"); |
| assertLine(docAdapter, 1, "ABCDEFGHIJ"); |
| assertLine(docAdapter, 2, "abcdefghij"); |
| assertLine(docAdapter, 3, "KLMNOPQRST"); |
| assertLine(docAdapter, 4, "kl"); |
| assertLine(docAdapter, 5, "UVWXYZ.,:;"); |
| assertEquals("Got wrong line.", 5, docAdapter.getLineAtOffset(docAdapter.getCharCount())); |
| checkLineMapping(docAdapter, rand); |
| |
| // replace text without length change |
| offset = docAdapter.getCharCount() - 3; |
| replaceText = "~~~"; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, replaceText, replaceText.length(), replaceText.length(), 0, 0)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, replaceText.length(), replaceText); |
| assertNumberOfLines(docAdapter, 6); |
| assertLine(docAdapter, 0, "0123456789"); |
| assertLine(docAdapter, 1, "ABCDEFGHIJ"); |
| assertLine(docAdapter, 2, "abcdefghij"); |
| assertLine(docAdapter, 3, "KLMNOPQRST"); |
| assertLine(docAdapter, 4, "kl"); |
| assertLine(docAdapter, 5, "UVWXYZ.~~~"); |
| assertEquals("Got wrong line.", 5, docAdapter.getLineAtOffset(docAdapter.getCharCount())); |
| checkLineMapping(docAdapter, rand); |
| |
| // insert text with one new line wrap |
| addText = ",:;"; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, addText, 0, addText.length(), 0, 1)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, 0, addText); |
| assertNumberOfLines(docAdapter, 7); |
| assertLine(docAdapter, 0, "0123456789"); |
| assertLine(docAdapter, 1, "ABCDEFGHIJ"); |
| assertLine(docAdapter, 2, "abcdefghij"); |
| assertLine(docAdapter, 3, "KLMNOPQRST"); |
| assertLine(docAdapter, 4, "kl"); |
| assertLine(docAdapter, 5, "UVWXYZ.,:;"); |
| assertLine(docAdapter, 6, "~~~"); |
| checkLineMapping(docAdapter, rand); |
| |
| // manipulate text so both document lines end at wrap border |
| addText = "mnopqrst"; |
| offset = 42; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, addText, 0, addText.length(), 0, 0)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, 0, addText); |
| replaceText = "uvwxyz_-=|"; |
| offset = docAdapter.getCharCount() - 3; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, replaceText, 3, replaceText.length(), 0, 0)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, 3, replaceText); |
| assertNumberOfLines(docAdapter, 7); |
| assertLine(docAdapter, 0, "0123456789"); |
| assertLine(docAdapter, 1, "ABCDEFGHIJ"); |
| assertLine(docAdapter, 2, "abcdefghij"); |
| assertLine(docAdapter, 3, "KLMNOPQRST"); |
| assertLine(docAdapter, 4, "klmnopqrst"); // <-- real line delimiter here |
| assertLine(docAdapter, 5, "UVWXYZ.,:;"); |
| assertLine(docAdapter, 6, "uvwxyz_-=|"); |
| assertEquals("Got wrong line.", 4, docAdapter.getLineAtOffset(49)); |
| assertEquals("Got wrong line.", 4, docAdapter.getLineAtOffset(50)); |
| assertEquals("Got wrong line.", 5, docAdapter.getLineAtOffset(51)); |
| assertEquals("Got wrong line.", 6, docAdapter.getLineAtOffset(docAdapter.getCharCount())); |
| checkLineMapping(docAdapter, rand); |
| |
| // remove last wrapped line |
| offset = docAdapter.getOffsetAtLine(docAdapter.getLineCount() - 1); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, "", 10, 0, 1, 0)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, 10, ""); |
| assertNumberOfLines(docAdapter, 6); |
| checkLineMapping(docAdapter, rand); |
| |
| // replace text ending at wrap border without new line wrap |
| replaceText = "~~~"; |
| offset = 7; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, replaceText, replaceText.length(), replaceText.length(), 0, 0)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, replaceText.length(), replaceText); |
| assertNumberOfLines(docAdapter, 6); |
| assertLine(docAdapter, 0, "0123456~~~"); |
| assertLine(docAdapter, 1, "ABCDEFGHIJ"); |
| checkLineMapping(docAdapter, rand); |
| |
| // remove 5th line including it's real line delimiter |
| offset = docAdapter.getOffsetAtLine(5 - 1); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, "", 11, 0, 1, 0)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, 11, ""); |
| assertNumberOfLines(docAdapter, 5); |
| assertLine(docAdapter, 3, "KLMNOPQRST"); |
| assertLine(docAdapter, 4, "UVWXYZ.,:;"); |
| checkLineMapping(docAdapter, rand); |
| |
| // remove text ending at wrap border |
| int remove = 3; |
| offset = 7; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, "", remove, 0, 4, 4)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, remove, ""); |
| assertNumberOfLines(docAdapter, 5); |
| assertLine(docAdapter, 0, "0123456ABC"); |
| assertLine(docAdapter, 1, "DEFGHIJabc"); |
| assertLine(docAdapter, 2, "defghijKLM"); |
| assertLine(docAdapter, 3, "NOPQRSTUVW"); |
| assertLine(docAdapter, 4, "XYZ.,:;"); |
| checkLineMapping(docAdapter, rand); |
| |
| assertFalse("Some expected change events were not received.", eventListener.hasPendingExpections()); |
| docAdapter.removeTextChangeListener(eventListener); |
| clearDocument(docAdapter); |
| } |
| |
| /** |
| * Test inserting text containing line delimiters. |
| */ |
| @Test |
| public void testMultilineInserts() { |
| final Random rand = new Random(4); |
| final int wrapWidth = 10; |
| final IDocumentAdapter docAdapter = new ConsoleDocumentAdapter(wrapWidth); |
| final ExpectingTextChangeListener eventListener = new ExpectingTextChangeListener(false, docAdapter); |
| assertEquals("Failed to set width.", wrapWidth, ((ConsoleDocumentAdapter) docAdapter).getWidth()); |
| docAdapter.setDocument(new Document()); |
| docAdapter.addTextChangeListener(eventListener); |
| |
| // add 4 new document lines with 1 line wrapped |
| String addText = "012345\nABCDEFGHIJa\r\n\nklmnopqrst\r\nuv"; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, 0, addText, 0, addText.length(), 0, 5)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(0, 0, addText); |
| assertNumberOfLines(docAdapter, 6); |
| assertLine(docAdapter, 0, "012345"); |
| assertLine(docAdapter, 1, "ABCDEFGHIJ"); |
| assertLine(docAdapter, 2, "a"); |
| assertLine(docAdapter, 3, ""); |
| assertLine(docAdapter, 4, "klmnopqrst"); |
| assertLine(docAdapter, 5, "uv"); |
| checkLineMapping(docAdapter, rand); |
| |
| // insert newline at begin of line |
| addText = "\n"; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, 0, addText, 0, addText.length(), 0, 1)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(0, 0, addText); |
| assertNumberOfLines(docAdapter, 7); |
| assertLine(docAdapter, 0, ""); |
| assertLine(docAdapter, 1, "012345"); |
| checkLineMapping(docAdapter, rand); |
| |
| // insert text + newline at begin of line |
| addText = "9876543210?\n"; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, 0, addText, 0, addText.length(), 0, 2)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(0, 0, addText); |
| assertNumberOfLines(docAdapter, 9); |
| assertLine(docAdapter, 0, "9876543210"); |
| assertLine(docAdapter, 1, "?"); |
| assertLine(docAdapter, 2, ""); |
| checkLineMapping(docAdapter, rand); |
| |
| // insert newline + text at begin of line |
| addText = "\r\nfoo"; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, 0, addText, 0, addText.length(), 1, 2)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(0, 0, addText); |
| assertNumberOfLines(docAdapter, 10); |
| assertLine(docAdapter, 0, ""); |
| assertLine(docAdapter, 1, "foo9876543"); |
| assertLine(docAdapter, 2, "210?"); |
| assertLine(docAdapter, 3, ""); |
| checkLineMapping(docAdapter, rand); |
| |
| // insert text + newline + text at begin of line |
| addText = ".,:;\r\nbar"; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, 0, addText, 0, addText.length(), 0, 1)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(0, 0, addText); |
| assertNumberOfLines(docAdapter, 11); |
| assertLine(docAdapter, 0, ".,:;"); |
| assertLine(docAdapter, 1, "bar"); |
| assertLine(docAdapter, 2, "foo9876543"); |
| checkLineMapping(docAdapter, rand); |
| |
| // insert 2 newline at end of line |
| addText = "\r\n\n"; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, docAdapter.getCharCount(), addText, 0, addText.length(), 0, 2)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, addText); |
| assertNumberOfLines(docAdapter, 13); |
| assertLine(docAdapter, 10, "uv"); |
| assertLine(docAdapter, 11, ""); |
| assertLine(docAdapter, 12, ""); |
| checkLineMapping(docAdapter, rand); |
| |
| // insert text + 2 newline at end of line (one line wrapping) |
| addText = "BCDEFGHIJKbc\n\n"; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, docAdapter.getCharCount(), addText, 0, addText.length(), 0, 3)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, addText); |
| assertNumberOfLines(docAdapter, 16); |
| assertLine(docAdapter, 12, "BCDEFGHIJK"); |
| assertLine(docAdapter, 13, "bc"); |
| assertLine(docAdapter, 14, ""); |
| assertLine(docAdapter, 15, ""); |
| checkLineMapping(docAdapter, rand); |
| |
| // insert 2 newline + text at end of line |
| addText = "\r\nLMNOPQR\nlmnopqrst"; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, docAdapter.getCharCount(), addText, 0, addText.length(), 0, 2)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, addText); |
| assertNumberOfLines(docAdapter, 18); |
| assertLine(docAdapter, 15, ""); |
| assertLine(docAdapter, 16, "LMNOPQR"); |
| assertLine(docAdapter, 17, "lmnopqrst"); |
| checkLineMapping(docAdapter, rand); |
| |
| // insert text + 2 newline + text at end of line (+one line wrapping) |
| addText = "uVW\nvwxy\r\n1357902468"; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, docAdapter.getCharCount(), addText, 0, addText.length(), 0, 3)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, addText); |
| assertNumberOfLines(docAdapter, 21); |
| assertLine(docAdapter, 17, "lmnopqrstu"); |
| assertLine(docAdapter, 18, "VW"); |
| assertLine(docAdapter, 19, "vwxy"); |
| assertLine(docAdapter, 20, "1357902468"); |
| checkLineMapping(docAdapter, rand); |
| |
| // insert newline inside (wrapped) line |
| int offset = docAdapter.getOffsetAtLine(17) + 8; |
| addText = "\n"; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, addText, 0, addText.length(), 1, 1)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, 0, addText); |
| assertNumberOfLines(docAdapter, 21); |
| assertLine(docAdapter, 17, "lmnopqrs"); |
| assertLine(docAdapter, 18, "tuVW"); |
| assertLine(docAdapter, 19, "vwxy"); |
| checkLineMapping(docAdapter, rand); |
| |
| // insert newline + text + newline in existing line |
| offset = docAdapter.getOffsetAtLine(19) + 2; |
| addText = "\n[()]\r\n"; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, addText, 0, addText.length(), 0, 2)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, 0, addText); |
| assertNumberOfLines(docAdapter, 23); |
| assertLine(docAdapter, 19, "vw"); |
| assertLine(docAdapter, 20, "[()]"); |
| assertLine(docAdapter, 21, "xy"); |
| checkLineMapping(docAdapter, rand); |
| |
| // insert newline + long text + newline in existing line |
| offset = docAdapter.getOffsetAtLine(20); |
| addText = "\r\nCDEFGHIJKLcdefghijklMNOPQR\n"; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, addText, 0, addText.length(), 0, 4)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, 0, addText); |
| assertNumberOfLines(docAdapter, 27); |
| assertLine(docAdapter, 20, ""); |
| assertLine(docAdapter, 21, "CDEFGHIJKL"); |
| assertLine(docAdapter, 22, "cdefghijkl"); |
| assertLine(docAdapter, 23, "MNOPQR"); |
| assertLine(docAdapter, 24, "[()]"); |
| checkLineMapping(docAdapter, rand); |
| |
| // insert newline inside (wrapped) line |
| offset = docAdapter.getOffsetAtLine(21) + 9; |
| addText = "\n"; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, addText, 0, addText.length(), 2, 2)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, 0, addText); |
| assertNumberOfLines(docAdapter, 27); |
| assertLine(docAdapter, 21, "CDEFGHIJK"); |
| assertLine(docAdapter, 22, "Lcdefghijk"); |
| assertLine(docAdapter, 23, "lMNOPQR"); |
| checkLineMapping(docAdapter, rand); |
| |
| assertFalse("Some expected change events were not received.", eventListener.hasPendingExpections()); |
| docAdapter.removeTextChangeListener(eventListener); |
| clearDocument(docAdapter); |
| } |
| |
| /** |
| * Test text remove affecting than one line. |
| */ |
| @Test |
| public void testMultilineRemove() { |
| final Random rand = new Random(4); |
| final int wrapWidth = 10; |
| final ExpectingTextChangeListener eventListener = new ExpectingTextChangeListener(true, null); |
| final IDocumentAdapter docAdapter = new ConsoleDocumentAdapter(wrapWidth); |
| assertEquals("Failed to set width.", wrapWidth, ((ConsoleDocumentAdapter) docAdapter).getWidth()); |
| docAdapter.setDocument(new Document()); |
| docAdapter.addTextChangeListener(eventListener); |
| |
| // prepare one wrapped line |
| clearDocument(docAdapter); |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, "0123456789"); |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, "ABCDE"); |
| // remove over wrap border but wrap remains |
| int offset = 8; |
| int remove = 4; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, "", remove, 0, 1, 1)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, remove, ""); |
| assertNumberOfLines(docAdapter, 2); |
| assertLine(docAdapter, 0, "01234567CD"); |
| assertLine(docAdapter, 1, "E"); |
| checkLineMapping(docAdapter, rand); |
| |
| // perform empty change event |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, 0, "", 0, 0, 0, 0)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(0, 0, ""); |
| assertFalse("Some expected change events were not received.", eventListener.hasPendingExpections()); |
| checkLineMapping(docAdapter, rand); |
| |
| // remove over wrap border (removes wrap) |
| offset = 8; |
| remove = 3; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, "", remove, 0, 1, 0)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, remove, ""); |
| assertNumberOfLines(docAdapter, 1); |
| assertLine(docAdapter, 0, "01234567"); |
| checkLineMapping(docAdapter, rand); |
| |
| // prepare one double wrapped line |
| clearDocument(docAdapter); |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, "0123456789"); |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, "ABCDEFGHIJ"); |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, "abcde"); |
| // remove over two wrap border |
| offset = 8; |
| remove = 14; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, "", remove, 0, 2, 1)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, remove, ""); |
| assertNumberOfLines(docAdapter, 2); |
| assertLine(docAdapter, 0, "01234567cd"); |
| assertLine(docAdapter, 1, "e"); |
| checkLineMapping(docAdapter, rand); |
| |
| // remove at fixed width border |
| offset = 10; |
| remove = 1; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, "", remove, 0, 1, 0)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, remove, ""); |
| assertNumberOfLines(docAdapter, 1); |
| assertLine(docAdapter, 0, "01234567cd"); |
| checkLineMapping(docAdapter, rand); |
| |
| // prepare two unwrapped lines |
| clearDocument(docAdapter); |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, "01234567\n"); |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, "ABCDEF"); |
| // remove line delimiter (produces wrapped line) |
| offset = 8; |
| remove = 1; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, "", remove, 0, 1, 1)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, remove, ""); |
| assertNumberOfLines(docAdapter, 2); |
| assertLine(docAdapter, 0, "01234567AB"); |
| assertLine(docAdapter, 1, "CDEF"); |
| checkLineMapping(docAdapter, rand); |
| |
| // prepare some more lines |
| clearDocument(docAdapter); |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, "01234567\n"); |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, "ABCDEFGHIJ"); |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, "abcdefghij"); |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, "KLMN\r\n"); |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, "klmno\n"); |
| assertLine(docAdapter, 5, ""); |
| // remove multiple lines |
| offset = 5; |
| remove = 36; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, "", remove, 0, 5, 0)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, remove, ""); |
| assertNumberOfLines(docAdapter, 1); |
| assertLine(docAdapter, 0, "01234"); |
| checkLineMapping(docAdapter, rand); |
| |
| // prepare more lines |
| clearDocument(docAdapter); |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, "01234567\n"); |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, "\n"); |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, "\r\n"); |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, "\n"); |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, docAdapter.getLineDelimiter()); |
| assertNumberOfLines(docAdapter, 6); |
| // remove empty lines |
| // (and do not start in first line like most tests before) |
| offset = 10; |
| remove = 3; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, "", remove, 0, 2, 0)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, remove, ""); |
| assertNumberOfLines(docAdapter, 4); |
| checkLineMapping(docAdapter, rand); |
| |
| assertFalse("Some expected change events were not received.", eventListener.hasPendingExpections()); |
| } |
| |
| /** |
| * Test text change affecting and inserting more than one line. |
| */ |
| @Test |
| public void testMultilineReplace() { |
| final Random rand = new Random(4); |
| final int wrapWidth = 10; |
| final ExpectingTextChangeListener eventListener = new ExpectingTextChangeListener(true, null); |
| final IDocumentAdapter docAdapter = new ConsoleDocumentAdapter(wrapWidth); |
| assertEquals("Failed to set width.", wrapWidth, ((ConsoleDocumentAdapter) docAdapter).getWidth()); |
| docAdapter.setDocument(new Document()); |
| docAdapter.addTextChangeListener(eventListener); |
| |
| docAdapter.setText("0123~~~AB"); |
| |
| // remove in single line and insert newline |
| String addText = "\n"; |
| int offset = 4; |
| int length = 3; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, addText, length, addText.length(), 0, 1)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, length, addText); |
| assertNumberOfLines(docAdapter, 2); |
| assertLine(docAdapter, 0, "0123"); // \n |
| assertLine(docAdapter, 1, "AB"); |
| checkLineMapping(docAdapter, rand); |
| |
| // replace newline with more text and a new newline |
| addText = "456789abc\r\n+"; |
| length = 2; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, addText, length, addText.length(), 1, 2)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, length, addText); |
| assertNumberOfLines(docAdapter, 3); |
| assertLine(docAdapter, 0, "0123456789"); |
| assertLine(docAdapter, 1, "abc"); // \r\n |
| assertLine(docAdapter, 2, "+B"); |
| checkLineMapping(docAdapter, rand); |
| |
| // remove and insert newline |
| addText = "<->\nABCDEFGHIJabc\n#"; |
| length = 12; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, addText, length, addText.length(), 2, 3)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, length, addText); |
| assertNumberOfLines(docAdapter, 4); |
| assertLine(docAdapter, 0, "0123<->"); // \n |
| assertLine(docAdapter, 1, "ABCDEFGHIJ"); |
| assertLine(docAdapter, 2, "abc"); // \n |
| assertLine(docAdapter, 3, "#B"); |
| checkLineMapping(docAdapter, rand); |
| |
| // insert newline and replace wrap |
| addText = "\n>=<"; |
| offset = 18; |
| length = 3; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, null, null, null, null, 1, 1)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, length, addText); |
| assertNumberOfLines(docAdapter, 4); |
| assertLine(docAdapter, 0, "0123<->"); // \n |
| assertLine(docAdapter, 1, "ABCDEFGHIJ"); // \n |
| assertLine(docAdapter, 2, ">=<"); // \n |
| assertLine(docAdapter, 3, "#B"); |
| checkLineMapping(docAdapter, rand); |
| |
| // replace last (real) line with new content |
| addText = "*+"; |
| offset = docAdapter.getCharCount() - 2; |
| length = 1; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, addText, length, addText.length(), 0, 0)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, length, addText); |
| assertNumberOfLines(docAdapter, 4); |
| assertLine(docAdapter, 2, ">=<"); // \n |
| assertLine(docAdapter, 3, "*+B"); |
| checkLineMapping(docAdapter, rand); |
| |
| // replace last character (at fixed width border) with new content |
| docAdapter.setText(""); |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, "0123456789"); |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, "ABCDEFGHIJ"); |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, "a"); |
| addText = "$b"; |
| offset = docAdapter.getCharCount() - 1; |
| length = 1; |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGING, offset, addText, length, addText.length(), 0, 0)); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.CHANGED)); |
| docAdapter.replaceTextRange(offset, length, addText); |
| assertNumberOfLines(docAdapter, 3); |
| assertLine(docAdapter, 1, "ABCDEFGHIJ"); |
| assertLine(docAdapter, 2, "$b"); |
| checkLineMapping(docAdapter, rand); |
| |
| assertFalse("Some expected change events were not received.", eventListener.hasPendingExpections()); |
| } |
| |
| /** |
| * Test line wrapping is correctly updated if fixed width changed. |
| */ |
| @Test |
| public void testSetWidth() { |
| final Random rand = new Random(7); |
| final ConsoleDocumentAdapter docAdapter = new ConsoleDocumentAdapter(-1); |
| docAdapter.setDocument(new Document()); |
| |
| final String line0_0 = "#123456789"; |
| final String line0_1 = "ABCDEF"; |
| final String line0 = line0_0 + line0_1; |
| final String line1 = ""; |
| final String line2 = "abcd"; |
| final String text = line0 + "\n" + line1 + "\r\n" + line2; |
| docAdapter.setText(text); |
| assertEquals("Get text range failed.", "#", docAdapter.getTextRange(0, 1)); |
| |
| // check with initial disabled fixed width mode |
| assertLine(docAdapter, 0, line0); |
| assertLine(docAdapter, 1, line1); |
| assertLine(docAdapter, 2, line2); |
| assertEquals("Adapter content length wrong.", text.length(), docAdapter.getCharCount()); |
| checkLineMapping(docAdapter, rand); |
| |
| // test with enabled fixed width mode |
| docAdapter.setWidth(10); |
| docAdapter.setWidth(10); // intentional double set |
| assertLine(docAdapter, 0, line0_0); |
| assertLine(docAdapter, 1, line0_1); |
| assertLine(docAdapter, 2, line1); |
| assertLine(docAdapter, 3, line2); |
| assertEquals("Adapter content length wrong.", text.length(), docAdapter.getCharCount()); |
| checkLineMapping(docAdapter, rand); |
| |
| // test with disabled fixed width mode after it was enabled |
| docAdapter.setWidth(-1); |
| assertLine(docAdapter, 0, line0); |
| assertLine(docAdapter, 1, line1); |
| assertLine(docAdapter, 2, line2); |
| assertEquals("Adapter content length wrong.", text.length(), docAdapter.getCharCount()); |
| checkLineMapping(docAdapter, rand); |
| |
| // test with fixed width mode but no virtual wrappings |
| docAdapter.setWidth(80); |
| assertLine(docAdapter, 0, line0); |
| assertLine(docAdapter, 1, line1); |
| assertLine(docAdapter, 2, line2); |
| assertEquals("Adapter content length wrong.", text.length(), docAdapter.getCharCount()); |
| checkLineMapping(docAdapter, rand); |
| |
| // add a listener for the next width change |
| final ExpectingTextChangeListener eventListener = new ExpectingTextChangeListener(false, docAdapter); |
| docAdapter.addTextChangeListener(eventListener); |
| eventListener.addExpectation(new TextEventExpectation(TextChangeEventType.SET)); |
| |
| // test extreme small console |
| docAdapter.setWidth(1); |
| int expectedLines = Math.max(line0.length(), 1); |
| expectedLines += Math.max(line1.length(), 1); |
| expectedLines += Math.max(line2.length(), 1); |
| assertNumberOfLines(docAdapter, expectedLines); |
| checkLineMapping(docAdapter, rand); |
| assertFalse("Some expected change events were not received.", eventListener.hasPendingExpections()); |
| } |
| |
| /** |
| * Some test cases derived from JavaDoc examples of {@link IDocumentAdapter} |
| * (and its super interfaces). |
| */ |
| @Test |
| public void testInterfaceContract() { |
| final ConsoleDocumentAdapter docAdapter = new ConsoleDocumentAdapter(-1); |
| docAdapter.setDocument(new Document()); |
| assertNotNull("Adapter has no legal line delimiter.", docAdapter.getLineDelimiter()); |
| |
| for (int width : new int[] { -1, 80 }) { |
| docAdapter.setWidth(width); |
| |
| // test against documentation of |
| // IDocumentAdapter#getLineAtOffset(int) |
| docAdapter.setText("\r\n\r\n"); |
| checkLineMapping(docAdapter, null); |
| assertEquals("Wrong line for offset.", 0, docAdapter.getLineAtOffset(0)); |
| assertEquals("Wrong line for offset.", 0, docAdapter.getLineAtOffset(1)); |
| assertEquals("Wrong line for offset.", 1, docAdapter.getLineAtOffset(2)); |
| assertEquals("Wrong line for offset.", 1, docAdapter.getLineAtOffset(3)); |
| assertEquals("Wrong line for offset.", 2, docAdapter.getLineAtOffset(4)); |
| assertEquals("Wrong line for offset.", docAdapter.getLineCount() - 1, docAdapter.getLineAtOffset(docAdapter.getCharCount())); |
| |
| // test against documentation of IDocumentAdapter#getLineCount() |
| docAdapter.setText(null); |
| assertNumberOfLines(docAdapter, 1); |
| docAdapter.setText(""); |
| assertNumberOfLines(docAdapter, 1); |
| docAdapter.setText("a\n"); |
| assertNumberOfLines(docAdapter, 2); |
| docAdapter.setText("\n\n"); |
| assertNumberOfLines(docAdapter, 3); |
| |
| // test against documentation of |
| // IDocumentAdapter#getOffsetAtLine(int) |
| docAdapter.setText("\r\ntest\r\n"); |
| checkLineMapping(docAdapter, null); |
| assertEquals("Wrong offset for line.", 0, docAdapter.getOffsetAtLine(0)); |
| assertEquals("Wrong offset for line.", 2, docAdapter.getOffsetAtLine(1)); |
| assertEquals("Wrong offset for line.", 8, docAdapter.getOffsetAtLine(2)); |
| docAdapter.setText(""); |
| assertEquals("Wrong offset for line.", 0, docAdapter.getOffsetAtLine(0)); |
| } |
| } |
| |
| /** |
| * Test |
| * {@link IDocumentAdapter#setDocument(org.eclipse.jface.text.IDocument)} |
| * and ensure old document is indeed disconnected and not notified anymore. |
| */ |
| @Test |
| public void testChangeDocument() { |
| final IDocumentAdapter docAdapter = new ConsoleDocumentAdapter(-1); |
| final IDocument doc1 = new Document(); |
| final IDocument doc2 = new Document(); |
| final String text1 = "foo"; |
| final String text2 = "bar"; |
| |
| docAdapter.setDocument(doc1); |
| docAdapter.setText(text1); |
| assertContent(docAdapter, text1); |
| |
| final String doc1Text = doc1.get(); |
| docAdapter.setDocument(doc2); |
| docAdapter.setText(text2); |
| assertContent(docAdapter, text2); |
| assertEquals("Document was changed after disconnect.", doc1Text, doc1.get()); |
| |
| docAdapter.setDocument(null); |
| } |
| |
| /** |
| * Test if invalid arguments produces error log messages. |
| */ |
| public void _testInvalidInvocations() { |
| final AtomicInteger expectedErrors = new AtomicInteger(0); |
| final ILogListener logListener = new ILogListener() { |
| @Override |
| public void logging(IStatus status, String plugin) { |
| if (status.matches(IStatus.ERROR)) { |
| expectedErrors.decrementAndGet(); |
| } |
| } |
| }; |
| try { |
| Platform.addLogListener(logListener); |
| |
| final ConsoleDocumentAdapter docAdapter = new ConsoleDocumentAdapter(-1); |
| docAdapter.setDocument(null); |
| docAdapter.setDocument(new Document()); |
| try { |
| docAdapter.addTextChangeListener(null); |
| fail("Exception not thrown."); |
| } catch (IllegalArgumentException ex) { |
| // expected behavior |
| } |
| try { |
| docAdapter.removeTextChangeListener(null); |
| fail("Exception not thrown."); |
| } catch (IllegalArgumentException ex) { |
| // expected behavior |
| } |
| |
| for (int width : new int[] { -1, -2, 80 }) { |
| docAdapter.setWidth(width); |
| if (width != -2) { |
| docAdapter.setText("?"); |
| } else { |
| // In non fixed mode the documents line tracker is used for |
| // most queries. Document may use different trackers if test |
| // is set or replaced. |
| docAdapter.replaceTextRange(0, docAdapter.getCharCount(), "?"); |
| } |
| |
| expectedErrors.set(3); |
| docAdapter.getLine(Integer.MIN_VALUE); |
| docAdapter.getLine(-1); |
| // getLine(1) should be invalid as well but the current |
| // implementation uses getLineInformation and ListLineTracker |
| // returns information for this non existing line and |
| // TreeLineTracke does so for compatibility reasons |
| docAdapter.getLine(Integer.MAX_VALUE); |
| assertEquals("Too much success with width: " + width, 0, expectedErrors.get()); |
| |
| expectedErrors.set(4); |
| docAdapter.getLineAtOffset(Integer.MIN_VALUE); |
| docAdapter.getLineAtOffset(-1); |
| docAdapter.getLineAtOffset(1); |
| docAdapter.getLineAtOffset(2); |
| docAdapter.getLineAtOffset(Integer.MAX_VALUE); |
| assertEquals("Too much success with width: " + width, 0, expectedErrors.get()); |
| |
| expectedErrors.set(4); |
| docAdapter.getOffsetAtLine(Integer.MIN_VALUE); |
| docAdapter.getOffsetAtLine(-1); |
| docAdapter.getOffsetAtLine(1); |
| docAdapter.getOffsetAtLine(Integer.MAX_VALUE); |
| assertEquals("Too much success with width: " + width, 0, expectedErrors.get()); |
| |
| expectedErrors.set(6); |
| docAdapter.getTextRange(-1, 1); |
| docAdapter.getTextRange(0, -1); |
| docAdapter.getTextRange(1, -1); |
| docAdapter.getTextRange(-1, 2); |
| docAdapter.getTextRange(0, 2); |
| docAdapter.getTextRange(0, 3); |
| assertEquals("Too much success with width: " + width, 0, expectedErrors.get()); |
| |
| expectedErrors.set(10); |
| docAdapter.replaceTextRange(2, 0, ""); |
| docAdapter.replaceTextRange(-1, 0, ""); |
| docAdapter.replaceTextRange(0, 2, ""); |
| docAdapter.replaceTextRange(0, -1, ""); |
| docAdapter.replaceTextRange(1, 1, ""); |
| docAdapter.replaceTextRange(0, 2, "foo"); |
| docAdapter.replaceTextRange(0, -1, "foo"); |
| docAdapter.replaceTextRange(1, 1, "foo"); |
| docAdapter.replaceTextRange(1, -1, "foo"); |
| docAdapter.replaceTextRange(2, 0, "foo"); |
| assertEquals("Too much success with width: " + width, 0, expectedErrors.get()); |
| } |
| } finally { |
| Platform.removeLogListener(logListener); |
| } |
| } |
| |
| /** |
| * Test adapter with a larger number of lines. (especially tests array grow) |
| */ |
| @Test |
| public void testManyLines() { |
| final ConsoleDocumentAdapter docAdapter = new ConsoleDocumentAdapter(80); |
| docAdapter.setDocument(new Document()); |
| final String lineDelimiter = docAdapter.getLineDelimiter(); |
| final int n = 6000; |
| for (int i = 0; i < n; i++) { |
| docAdapter.replaceTextRange(docAdapter.getCharCount(), 0, lineDelimiter); |
| } |
| assertNumberOfLines(docAdapter, n + 1); |
| docAdapter.setWidth(-1); |
| assertNumberOfLines(docAdapter, n + 1); |
| clearDocument(docAdapter); |
| } |
| |
| private static void assertContent(IDocumentAdapter docAdapter, String content) { |
| assertEquals("Adapter returned wrong content.", content, docAdapter.getTextRange(0, docAdapter.getCharCount())); |
| } |
| |
| private static void assertNumberOfLines(IDocumentAdapter docAdapter, int expectedLines) { |
| assertEquals("Adapter has wrong line count.", expectedLines, docAdapter.getLineCount()); |
| } |
| |
| private static void assertLine(IDocumentAdapter docAdapter, int lineIndex, String expectedContent) { |
| assertEquals("Adapter returned wrong content for line " + lineIndex + ".", expectedContent, docAdapter.getLine(lineIndex)); |
| } |
| |
| /** |
| * Goes through every line in adapted document and checks if value of |
| * {@link IDocumentAdapter#getOffsetAtLine(int)} for a line returns the same |
| * line again if put into {@link IDocumentAdapter#getLineAtOffset(int)}. |
| * <p> |
| * If random source is provided test is more intensive and to some extend |
| * tests {@link IDocumentAdapter#getLine(int)}. |
| * </p> |
| * |
| * @param docAdapter document adapter to test |
| * @param rand Optional. If provided will request line from random offset of |
| * this line instead of first and check lines in random order. |
| */ |
| private static void checkLineMapping(IDocumentAdapter docAdapter, Random rand) { |
| final int n = docAdapter.getLineCount(); |
| final List<Integer> lines = new ArrayList<>(n); |
| for (int i = 0; i < n; i++) { |
| lines.add(i); |
| } |
| if (rand != null) { |
| Collections.shuffle(lines, rand); |
| } |
| for (int lineIndex : lines) { |
| int offset = docAdapter.getOffsetAtLine(lineIndex); |
| if (rand != null) { |
| int lineLength = docAdapter.getLine(lineIndex).length(); |
| if (lineLength > 0) { |
| offset += rand.nextInt(lineLength); |
| } |
| } |
| final int testLineIndex = docAdapter.getLineAtOffset(offset); |
| assertEquals("Got wrong line with offset " + offset + ".", lineIndex, testLineIndex); |
| } |
| } |
| |
| private static void clearDocument(IDocumentAdapter docAdapter) { |
| docAdapter.setText(""); |
| assertEquals("Document not cleared.", 0, docAdapter.getCharCount()); |
| assertNumberOfLines(docAdapter, 1); |
| assertLine(docAdapter, 0, ""); |
| } |
| |
| private static class TextEventExpectation { |
| // common attributes |
| /** Expected text change event type. */ |
| public final TextChangeEventType type; |
| |
| // text changing only attributes |
| /** |
| * Expected value of {@link TextChangingEvent#start} or |
| * <code>null</code> to ignore. |
| */ |
| public final Integer start; |
| /** |
| * Expected value of {@link TextChangingEvent#newText} or |
| * <code>null</code> to ignore. |
| */ |
| public final String newText; |
| /** |
| * Expected value of {@link TextChangingEvent#replaceCharCount} or |
| * <code>null</code> to ignore. |
| */ |
| public final Integer replaceCharCount; |
| /** |
| * Expected value of {@link TextChangingEvent#newCharCount} or |
| * <code>null</code> to ignore. |
| */ |
| public final Integer newCharCount; |
| /** |
| * Expected value of {@link TextChangingEvent#replaceLineCount} or |
| * <code>null</code> to ignore. |
| */ |
| public final Integer replaceLineCount; |
| /** |
| * Expected value of {@link TextChangingEvent#newLineCount} or |
| * <code>null</code> to ignore. |
| */ |
| public final Integer newLineCount; |
| |
| public TextEventExpectation(TextChangeEventType type) { |
| this(type, null, null, null, null, null, null); |
| } |
| |
| public TextEventExpectation(TextChangeEventType type, Integer start, String newText, Integer replaceCharCount, Integer newCharCount, Integer replaceLineCount, Integer newLineCount) { |
| super(); |
| this.type = type; |
| this.start = start; |
| this.newText = newText; |
| this.replaceCharCount = replaceCharCount; |
| this.newCharCount = newCharCount; |
| this.replaceLineCount = replaceLineCount; |
| this.newLineCount = newLineCount; |
| } |
| } |
| |
| /** |
| * A {@link TextChangeListener} which has some expectations about generated |
| * text change events and is not gladly disappointed. |
| */ |
| private static class ExpectingTextChangeListener implements TextChangeListener { |
| |
| final Queue<TextEventExpectation> expectations = new LinkedList<>(); |
| final boolean allowUnexpectedEvents; |
| /** |
| * The {@link IDocumentAdapter} generating the events. If set some |
| * additional checks are performed. |
| */ |
| final IDocumentAdapter docAdapter; |
| /** |
| * If all events are checked ({@link #allowUnexpectedEvents} = false) |
| * and {@link #docAdapter} is set do some additional validations. |
| */ |
| TextChangingEvent lastEvent; |
| int eventLineBeforeChange = -1; |
| int linesBeforeReplace = -1; |
| int lengthBeforeReplace = -1; |
| |
| public ExpectingTextChangeListener(boolean allowUnexpectedEvents, IDocumentAdapter docAdapter) { |
| super(); |
| this.allowUnexpectedEvents = allowUnexpectedEvents; |
| this.docAdapter = docAdapter; |
| } |
| |
| public void addExpectation(TextEventExpectation expectation) { |
| expectations.add(expectation); |
| } |
| |
| @Override |
| public void textChanging(TextChangingEvent event) { |
| final TextEventExpectation expectation = checkCommon(TextChangeEventType.CHANGING); |
| if (expectation != null) { |
| if (expectation.start != null) { |
| assertEquals("event.start", (int) expectation.start, event.start); |
| } |
| if (expectation.newText != null) { |
| assertEquals("event.newText", expectation.newText, event.newText); |
| } |
| if (expectation.replaceCharCount != null) { |
| assertEquals("event.replaceCharCount", (int) expectation.replaceCharCount, event.replaceCharCount); |
| } |
| if (expectation.newCharCount != null) { |
| assertEquals("event.newCharCount", (int) expectation.newCharCount, event.newCharCount); |
| } |
| if (expectation.replaceLineCount != null) { |
| assertEquals("event.replaceLineCount", (int) expectation.replaceLineCount, event.replaceLineCount); |
| } |
| if (expectation.newLineCount != null) { |
| assertEquals("event.newLineCount", (int) expectation.newLineCount, event.newLineCount); |
| } |
| } |
| |
| if (!allowUnexpectedEvents && docAdapter != null) { |
| lastEvent = event; |
| eventLineBeforeChange = docAdapter.getLineAtOffset(event.start); |
| linesBeforeReplace = docAdapter.getLineCount(); |
| lengthBeforeReplace = docAdapter.getCharCount(); |
| |
| final int charactersBehindEventStart = docAdapter.getCharCount() - event.start; |
| assertTrue("Tried to remove more characters than available.", event.replaceCharCount <= charactersBehindEventStart); |
| |
| final int linesBehindEvent = docAdapter.getLineCount() - docAdapter.getLineAtOffset(event.start); |
| assertTrue("Tried to remove more lines than available.", event.replaceLineCount <= linesBehindEvent); |
| } |
| } |
| |
| @Override |
| public void textChanged(TextChangedEvent event) { |
| checkCommon(TextChangeEventType.CHANGED); |
| |
| if (docAdapter != null && lastEvent != null) { |
| final int lastEventOffset = lastEvent.start; |
| final int lastEventLineIndex = docAdapter.getLineAtOffset(lastEventOffset); |
| assertTrue("Line of event offset " + lastEventOffset + " has moved up.", eventLineBeforeChange <= lastEventLineIndex); |
| |
| // check if predicted changes are correct |
| final int predictedDocLength = lengthBeforeReplace - lastEvent.replaceCharCount + lastEvent.newCharCount; |
| assertEquals("New widget length not as announce by changing event.", predictedDocLength, docAdapter.getCharCount()); |
| final int predictedDocLines = linesBeforeReplace - lastEvent.replaceLineCount + lastEvent.newLineCount; |
| assertEquals("New widget line number not as announce by changing event.", predictedDocLines, docAdapter.getLineCount()); |
| assertEquals("Inserted text not found in document.", lastEvent.newText, docAdapter.getTextRange(lastEvent.start, lastEvent.newText.length())); |
| } |
| } |
| |
| @Override |
| public void textSet(TextChangedEvent event) { |
| checkCommon(TextChangeEventType.SET); |
| } |
| |
| public boolean hasPendingExpections() { |
| return !expectations.isEmpty(); |
| } |
| |
| private TextEventExpectation checkCommon(TextChangeEventType eventType) { |
| final TextEventExpectation expectation = expectations.poll(); |
| if (expectation == null && allowUnexpectedEvents) { |
| return null; |
| } |
| assertNotNull("Unexpected event.", expectation); |
| if (expectation.type != eventType && allowUnexpectedEvents) { |
| return null; |
| } |
| assertEquals("Wrong event type.", expectation.type, eventType); |
| return expectation; |
| } |
| } |
| |
| public enum TextChangeEventType { |
| CHANGING, CHANGED, SET, |
| } |
| } |