blob: 02205f1d6f89f80e55d90d3332de9752d98abac6 [file] [log] [blame]
/*******************************************************************************
* 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 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;
/**
* Tests {@link ConsoleDocumentAdapter}.
* <p>
* Primary tests fixed width mode and calculation of {@link TextChangingEvent}s.
* </p>
*/
@SuppressWarnings("restriction")
public class ConsoleDocumentAdapterTests extends AbstractDebugTest {
public ConsoleDocumentAdapterTests() {
super(ConsoleDocumentAdapterTests.class.getSimpleName());
}
public ConsoleDocumentAdapterTests(String name) {
super(name);
}
/**
* Test {@link ConsoleDocumentAdapter#setText(String)}.
*/
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)
*/
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, null, null, null, null, 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, null, null, null, null, 1, 1));
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, null, null, null, null, 1, 1));
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, null, null, null, null, 1, 1));
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, null, null, null, null, 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, null, null, null, null, null, null));
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.
*/
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.
*/
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, null, null, null, null, 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.
*/
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);
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);
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, null, null, null, null, 1, 1));
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.
*/
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).
*/
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.
*/
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)
*/
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 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) {
return;
}
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;
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);
assertEquals("Line of offset " + lastEventOffset + " has changed after text change.", lastEventLineIndex, docAdapter.getLineAtOffset(lastEventOffset));
// 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 == null) {
// prevents wrong compiler warning 'expectation may be null'
return null;
}
if (expectation.type != eventType && allowUnexpectedEvents) {
return null;
}
assertEquals("Wrong event type.", expectation.type, eventType);
return expectation;
}
}
public enum TextChangeEventType {
CHANGING, CHANGED, SET,
}
}