blob: 7e396cc1c67ea6f66c5cdd73f6246eaa46b425a0 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012, 2013 Florian Thienel and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Florian Thienel - initial API and implementation
* Carsten Hiesserich - additional tests (bug 407827, 409032)
*******************************************************************************/
package org.eclipse.vex.core.internal.widget;
import static org.eclipse.vex.core.internal.widget.VexWidgetTest.PARA;
import static org.eclipse.vex.core.internal.widget.VexWidgetTest.PRE;
import static org.eclipse.vex.core.internal.widget.VexWidgetTest.TITLE;
import static org.eclipse.vex.core.internal.widget.VexWidgetTest.createDocumentWithDTD;
import static org.eclipse.vex.core.tests.TestResources.TEST_DTD;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.util.List;
import org.eclipse.vex.core.internal.css.CssWhitespacePolicy;
import org.eclipse.vex.core.internal.css.StyleSheet;
import org.eclipse.vex.core.internal.css.StyleSheetReader;
import org.eclipse.vex.core.provisional.dom.IDocumentFragment;
import org.eclipse.vex.core.provisional.dom.IElement;
import org.eclipse.vex.core.provisional.dom.INode;
import org.eclipse.vex.core.provisional.dom.IParent;
import org.eclipse.vex.core.provisional.dom.IText;
import org.eclipse.vex.core.tests.TestResources;
import org.junit.Before;
import org.junit.Test;
/**
* @author Florian Thienel
*/
public class L2SimpleEditingTest {
private IVexWidget widget;
private IElement rootElement;
@Before
public void setUp() throws Exception {
widget = new BaseVexWidget(new MockHostComponent());
widget.setDocument(createDocumentWithDTD(TEST_DTD, "section"), readTestStyleSheet());
widget.setWhitespacePolicy(new CssWhitespacePolicy(widget.getStyleSheet()));
rootElement = widget.getDocument().getRootElement();
}
@Test
public void shouldStartInRootElement() throws Exception {
assertSame(rootElement, widget.getCurrentElement());
assertEquals(rootElement.getEndOffset(), widget.getCaretOffset());
}
@Test
public void shouldMoveCaretIntoInsertedElement() throws Exception {
final IElement titleElement = widget.insertElement(TITLE);
assertEquals(titleElement.getEndOffset(), widget.getCaretOffset());
}
@Test
public void shouldProvideInsertionElementAsCurrentElement() throws Exception {
final IElement titleElement = widget.insertElement(TITLE);
widget.moveBy(-1);
assertEquals(titleElement.getStartOffset(), widget.getCaretOffset());
assertSame(rootElement, widget.getCurrentElement());
}
@Test
public void givenAnElementWithText_whenAtEndOfTextAndHittingBackspace_shouldDeleteLastCharacter() throws Exception {
final IElement titleElement = widget.insertElement(TITLE);
widget.insertText("Hello");
widget.deletePreviousChar();
assertEquals("Hell", titleElement.getText());
assertEquals(titleElement.getEndOffset(), widget.getCaretOffset());
}
@Test
public void givenAnElementWithText_whenAtBeginningOfTextAndHittingDelete_shouldDeleteFirstCharacter() throws Exception {
final IElement titleElement = widget.insertElement(TITLE);
widget.insertText("Hello");
widget.moveBy(-5);
widget.deleteNextChar();
assertEquals("ello", titleElement.getText());
assertEquals(titleElement.getStartOffset() + 1, widget.getCaretOffset());
}
@Test
public void givenAnEmptyElement_whenCaretBetweenStartAndEndTagAndHittingBackspace_shouldDeleteEmptyElement() throws Exception {
widget.insertElement(TITLE);
widget.moveBy(1);
final IElement paraElement = widget.insertElement(PARA);
widget.deletePreviousChar();
assertEquals(1, rootElement.children().count());
assertNull(paraElement.getParent());
assertFalse(paraElement.isAssociated());
}
@Test
public void givenAnEmptyElement_whenCaretBetweenStartAndEndTagAndHittingDelete_shouldDeleteEmptyElement() throws Exception {
widget.insertElement(TITLE);
widget.moveBy(1);
final IElement paraElement = widget.insertElement(PARA);
widget.deleteNextChar();
assertEquals(1, rootElement.children().count());
assertNull(paraElement.getParent());
assertFalse(paraElement.isAssociated());
}
@Test
public void givenAnEmptyElement_whenCaretAfterEndTagAndHittingDelete_shouldDeleteEmptyElement() throws Exception {
widget.insertElement(TITLE);
widget.moveBy(1);
final IElement paraElement = widget.insertElement(PARA);
widget.moveBy(1);
widget.deletePreviousChar();
assertEquals(1, rootElement.children().count());
assertNull(paraElement.getParent());
assertFalse(paraElement.isAssociated());
}
@Test
public void givenAnEmptyElement_whenCaretBeforeStartTagAndHittingDelete_shouldDeleteEmptyElement() throws Exception {
widget.insertElement(TITLE);
widget.moveBy(1);
final IElement paraElement = widget.insertElement(PARA);
widget.moveBy(-1);
widget.deleteNextChar();
assertEquals(1, rootElement.children().count());
assertNull(paraElement.getParent());
assertFalse(paraElement.isAssociated());
}
@Test
public void givenTwoMatchingElements_whenCaretBetweenEndAndStartTagAndHittingBackspace_shouldJoinElements() throws Exception {
widget.insertElement(TITLE);
widget.moveBy(1);
final IElement para1 = widget.insertElement(PARA);
widget.insertText("Hello");
widget.moveBy(1);
final IElement para2 = widget.insertElement(PARA);
widget.insertText("World");
widget.moveTo(para2.getStartOffset());
widget.deletePreviousChar();
assertEquals(2, rootElement.children().count());
assertSame(rootElement, para1.getParent());
assertTrue(para1.isAssociated());
assertEquals("HelloWorld", para1.getText());
assertNull(para2.getParent());
assertFalse(para2.isAssociated());
}
@Test
public void givenTwoMatchingElements_whenCaretBetweenEndAndStartTagAndHittingDelete_shouldJoinElements() throws Exception {
widget.insertElement(TITLE);
widget.moveBy(1);
final IElement para1 = widget.insertElement(PARA);
widget.insertText("Hello");
widget.moveBy(1);
final IElement para2 = widget.insertElement(PARA);
widget.insertText("World");
widget.moveTo(para2.getStartOffset());
widget.deleteNextChar();
assertEquals(2, rootElement.children().count());
assertSame(rootElement, para1.getParent());
assertTrue(para1.isAssociated());
assertEquals("HelloWorld", para1.getText());
assertNull(para2.getParent());
assertFalse(para2.isAssociated());
}
@Test
public void givenTwoMatchingElements_whenCaretAfterStartTagOfSecondElementAndHittingBackspace_shouldJoinElements() throws Exception {
widget.insertElement(TITLE);
widget.moveBy(1);
final IElement para1 = widget.insertElement(PARA);
widget.insertText("Hello");
widget.moveBy(1);
final IElement para2 = widget.insertElement(PARA);
widget.insertText("World");
widget.moveTo(para2.getStartOffset() + 1);
widget.deletePreviousChar();
assertEquals(2, rootElement.children().count());
assertSame(rootElement, para1.getParent());
assertTrue(para1.isAssociated());
assertEquals("HelloWorld", para1.getText());
assertNull(para2.getParent());
assertFalse(para2.isAssociated());
}
@Test
public void givenTwoMatchingElements_whenCaretBeforeEndTagOfFirstElementAndHittingDelete_shouldJoinElements() throws Exception {
widget.insertElement(TITLE);
widget.moveBy(1);
final IElement para1 = widget.insertElement(PARA);
widget.insertText("Hello");
widget.moveBy(1);
final IElement para2 = widget.insertElement(PARA);
widget.insertText("World");
widget.moveTo(para1.getEndOffset());
widget.deleteNextChar();
assertEquals(2, rootElement.children().count());
assertSame(rootElement, para1.getParent());
assertTrue(para1.isAssociated());
assertEquals("HelloWorld", para1.getText());
assertNull(para2.getParent());
assertFalse(para2.isAssociated());
}
@Test
public void givenElementWithText_whenAllTextSelectedAndInsertingACharacter_shouldReplaceAllTextWithNewCharacter() throws Exception {
final IElement titleElement = widget.insertElement(TITLE);
widget.insertText("Hello World");
widget.moveTo(titleElement.getStartOffset() + 1, true);
widget.insertChar('A');
assertEquals("A", titleElement.getText());
}
@Test(expected = ReadOnlyException.class)
public void whenReadOnly_shouldNotInsertText() throws Exception {
widget.insertElement(TITLE); // need an element where text would be valid
widget.setReadOnly(true);
assertFalse(widget.canInsertText());
widget.insertText("Hello World");
}
@Test(expected = ReadOnlyException.class)
public void whenReadOnly_shouldNotInsertChar() throws Exception {
widget.insertElement(TITLE); // need an element where text would be valid
widget.setReadOnly(true);
assertFalse(widget.canInsertText());
widget.insertChar('H');
}
@Test(expected = ReadOnlyException.class)
public void whenReadOnly_shouldNotInsertElement() throws Exception {
widget.setReadOnly(true);
assertTrue(widget.getValidInsertElements().length == 0);
widget.insertElement(TITLE);
}
@Test(expected = ReadOnlyException.class)
public void whenReadOnly_shouldNotInsertComment() throws Exception {
widget.setReadOnly(true);
assertFalse(widget.canInsertComment());
widget.insertComment();
}
@Test(expected = ReadOnlyException.class)
public void whenReadOnly_shouldNotInsertFragment() throws Exception {
widget.insertElement(TITLE);
widget.moveBy(1);
final IElement para = widget.insertElement(PARA);
final IDocumentFragment fragment = widget.getDocument().getFragment(para.getRange());
widget.moveTo(rootElement.getEndOffset());
widget.setReadOnly(true);
assertFalse(widget.canInsertFragment(fragment));
widget.insertFragment(fragment);
}
@Test
public void givenNonPreElement_whenInsertingNewline_shouldSplitElement() throws Exception {
widget.insertElement(TITLE);
widget.moveBy(1);
final IElement para1 = widget.insertElement(PARA);
widget.insertText("Hello");
widget.moveTo(para1.getEndOffset());
widget.insertText("\n");
assertEquals("Hello", para1.getText());
assertEquals(3, rootElement.children().count());
}
@Test
public void givenPreElement_whenInsertingNewline_shouldInsertNewline() throws Exception {
final IElement para = widget.insertElement(PARA);
final IElement preElement = widget.insertElement(PRE);
assertEquals(preElement.getEndOffset(), widget.getCaretOffset());
widget.insertText("line1");
widget.insertText("\n");
assertEquals(1, para.children().count());
assertEquals("line1\n", preElement.getText());
}
@Test
public void insertingTextAtInvalidPosition_shouldNotAlterDocument() throws Exception {
final IElement para1 = widget.insertElement(PARA);
widget.moveBy(1);
final IElement para2 = widget.insertElement(PARA);
widget.moveTo(para1.getEndOffset());
widget.insertText("Para1");
widget.moveTo(para2.getEndOffset());
widget.insertText("Para2");
// Insert position is invalid
widget.moveTo(para1.getEndOffset() + 1);
try {
widget.insertText("Test");
} catch (final Exception ex) {
} finally {
assertEquals("Para1", para1.getText());
assertEquals("Para2", para2.getText());
}
}
@Test
public void insertingElementAtInvalidPosition_shouldNotAlterDocument() throws Exception {
final IElement para1 = widget.insertElement(PARA);
widget.moveBy(1);
final IElement para2 = widget.insertElement(PARA);
widget.moveTo(para1.getEndOffset());
widget.insertText("Para1");
widget.moveTo(para2.getEndOffset());
widget.insertText("Para2");
// Insert position is invalid
widget.moveTo(para1.getEndOffset());
try {
widget.insertElement(PARA);
} catch (final Exception ex) {
} finally {
assertEquals("Para1", para1.getText());
assertEquals("Para2", para2.getText());
}
}
@Test
public void givenPreElement_whenInsertingTextWithNewline_shouldInsertNewline() throws Exception {
widget.insertElement(PARA);
final IElement preElement = widget.insertElement(PRE);
assertEquals(preElement.getEndOffset(), widget.getCaretOffset());
widget.insertText("line1\nline2");
assertEquals("line1\nline2", preElement.getText());
}
@Test
public void givenPreElement_whenInsertingText_shouldKeepWhitespace() throws Exception {
widget.insertElement(PARA);
final IElement preElement = widget.insertElement(PRE);
widget.moveTo(preElement.getEndOffset());
widget.insertText("line1\nline2 end");
final List<? extends INode> children = preElement.children().asList();
assertTrue("Expecting IText", children.get(0) instanceof IText);
assertEquals("line1\nline2 end", children.get(0).getText());
}
@Test
public void givenNonPreElement_whenInsertingText_shouldCompressWhitespace() throws Exception {
final IElement para = widget.insertElement(PARA);
widget.moveTo(para.getEndOffset());
widget.insertText("line1\nline2 \t end");
final List<? extends INode> children = rootElement.children().after(para.getStartOffset()).asList();
assertEquals("two para elements", 2, children.size());
assertTrue("original para element", children.get(0) instanceof IParent);
assertTrue("splitted para element", children.get(1) instanceof IParent);
assertEquals("first line", "line1", children.get(0).getText());
assertEquals("second line with compressed whitespace", "line2 end", children.get(1).getText());
}
@Test
public void givenNonPreElement_whenInsertingText_shouldCompressNewlines() throws Exception {
final IElement para = widget.insertElement(PARA);
widget.moveTo(para.getEndOffset());
widget.insertText("line1\n\nline2");
final List<? extends INode> children = rootElement.children().after(para.getStartOffset()).asList();
assertEquals("two para elements", 2, children.size());
assertTrue("original para element", children.get(0) instanceof IParent);
assertTrue("splitted para element", children.get(1) instanceof IParent);
assertEquals("first line", "line1", children.get(0).getText());
assertEquals("second line", "line2", children.get(1).getText());
}
@Test
public void givenNonPreElement_whenSplitting_shouldSplitIntoTwoElements() throws Exception {
final IElement para = widget.insertElement(PARA);
widget.moveTo(para.getEndOffset());
widget.insertText("line1line2");
widget.moveBy(-5);
widget.split();
final List<? extends INode> children = rootElement.children().after(para.getStartOffset()).asList();
assertEquals("two para elements", 2, children.size());
assertTrue("original para element", children.get(0) instanceof IParent);
assertTrue("splitted para element", children.get(1) instanceof IParent);
assertEquals("first line element", PARA, ((IElement) children.get(0)).getQualifiedName());
assertEquals("second line element", PARA, ((IElement) children.get(0)).getQualifiedName());
assertEquals("first line", "line1", children.get(0).getText());
assertEquals("second line", "line2", children.get(1).getText());
}
@Test
public void givenPreElement_whenSplitting_shouldSplitIntoTwoElements() throws Exception {
final IElement para = widget.insertElement(PARA);
final IElement preElement = widget.insertElement(PRE);
widget.moveTo(preElement.getEndOffset());
widget.insertText("line1line2");
widget.moveBy(-5);
widget.split();
final List<? extends INode> children = para.children().after(preElement.getStartOffset()).asList();
assertEquals("two para elements", 2, children.size());
assertTrue("original pre element", children.get(0) instanceof IParent);
assertTrue("splitted pre element", children.get(1) instanceof IParent);
assertEquals("first line element", PRE, ((IElement) children.get(0)).getQualifiedName());
assertEquals("second line element", PRE, ((IElement) children.get(0)).getQualifiedName());
assertEquals("first line", "line1", children.get(0).getText());
assertEquals("second line", "line2", children.get(1).getText());
}
private static StyleSheet readTestStyleSheet() throws IOException {
return new StyleSheetReader().read(TestResources.get("test.css"));
}
}