Package org.waveprotocol.wave.model.document.util

Source Code of org.waveprotocol.wave.model.document.util.LineContainersTest$LineTestState

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.waveprotocol.wave.model.document.util;


import junit.framework.TestCase;

import org.waveprotocol.wave.model.document.MutableDocument;
import org.waveprotocol.wave.model.document.operation.automaton.DocumentSchema;
import org.waveprotocol.wave.model.document.operation.impl.AttributesImpl;
import org.waveprotocol.wave.model.document.raw.impl.Element;
import org.waveprotocol.wave.model.document.raw.impl.Node;
import org.waveprotocol.wave.model.document.raw.impl.Text;
import org.waveprotocol.wave.model.document.util.ContextProviders.TestDocumentContext;
import org.waveprotocol.wave.model.document.util.LineContainers.RoundDirection;
import org.waveprotocol.wave.model.document.util.LineContainers.Rounding;
import org.waveprotocol.wave.model.schema.AbstractXmlSchemaConstraints;

import java.util.Collections;
import java.util.List;

/**
* @author danilatos@google.com (Daniel Danilatos)
*/

public class LineContainersTest extends TestCase {

  private final DocumentSchema SCHEMA = new AbstractXmlSchemaConstraints() {
    {
      addChildren(null, "body");

      addChildren("body", "line", "input");
      containsBlipText("body");
      containsBlipText("input");

      addRequiredInitial("body", Collections.singletonList("line"));

      addAttrWithValues("line", "t", "h1", "h2", "h3", "h4", "li");
    }
  };

  private TestDocumentContext<Node, Element, Text> cxt;
  private MutableDocument<Node, Element, Text> doc;

  @Override
  protected void setUp() throws Exception {
    LineContainers.setTopLevelContainerTagname("body");
  }

  public void testTopLevelContainerTagName() {
    LineContainers.setTopLevelContainerTagname("blah");
    assertEquals("blah", LineContainers.topLevelContainerTagname());
    LineContainers.setTopLevelContainerTagname("body");
    assertEquals("body", LineContainers.topLevelContainerTagname());
    try {
      LineContainers.setTopLevelContainerTagname(null);
      fail("null should be rejected");
    } catch (RuntimeException e) {
      // ok
    }
  }

  public void testWrappers() {
    assertEquals("<line></line>foo", LineContainers.debugLineWrap("foo"));
    assertEquals("<body></body>", LineContainers.debugContainerWrap());
    assertEquals("<body><line></line>foo</body>", LineContainers.debugContainerWrap("foo"));
    assertEquals("<body><line></line>foo<line></line>bar</body>",
        LineContainers.debugContainerWrap("foo", "bar"));
  }

  private class LineTestState {
    {
      getDocWithoutSchema("<body><line/>abc<x>def<line id=\"bad\"/></x>."
          + "<line id=\"2\"/><line id=\"3\"/>ghi</body>jkl");
    }
    Element lc = DocHelper.getElementWithTagName(doc, "body");
    Point<Node> beforeLine = Point.before(doc, DocHelper.getElementWithTagName(doc, "line"));
    Point<Node> afterLine = Point.after(doc, DocHelper.getElementWithTagName(doc, "line"));
    Point<Node> inAbc = Point.inText(afterLine.getNodeAfter(), 2);
    Element x = DocHelper.getElementWithTagName(doc, "x");
    Point<Node> inX = Point.start(doc, x);
    Point<Node> afterX = Point.after(doc, x);
    Point<Node> beforeInvalidLine = Point.before(doc, DocHelper.findElementById(doc, "bad"));
    Point<Node> beforeLine2 = Point.before(doc, DocHelper.findElementById(doc, "2"));
    Point<Node> beforeLine3 = Point.before(doc, DocHelper.findElementById(doc, "3"));
    Point<Node> endLc = Point.<Node>end(lc);
    Point<Node> inGhi = Point.inText(endLc.getContainer().getLastChild(), 2);
    Point<Node> endGhi = Point.inText(endLc.getContainer().getLastChild(), 3);
  }

  public void testEndOfLineCheck() {
    LineTestState s = new LineTestState();

    // Consider having this be satisfied:
    // assertFalse(LineContainers.isAtLineEnd(doc, s.beforeLine));

    assertTrue(LineContainers.isAtLineEnd(doc, s.beforeLine2));
    assertTrue(LineContainers.isAtLineEnd(doc, s.beforeLine3));
    assertFalse(LineContainers.isAtLineEnd(doc, s.inAbc));
    assertFalse(LineContainers.isAtLineEnd(doc, s.inX));
    s.afterX = doc.deleteRange(s.afterX, s.beforeLine2).getSecond();
    assertTrue(LineContainers.isAtLineEnd(doc, s.afterX));
    assertFalse(LineContainers.isAtLineEnd(doc, s.inGhi));
    assertTrue(LineContainers.isAtLineEnd(doc, s.endGhi));
  }

  public void testStartOfLineCheck() {
    LineTestState s = new LineTestState();
    assertTrue(LineContainers.isAtLineStart(doc, s.afterLine));
    assertFalse(LineContainers.isAtLineStart(doc, s.beforeLine2));
    assertTrue(LineContainers.isAtLineStart(doc, s.beforeLine3));
    assertFalse(LineContainers.isAtLineStart(doc, s.inAbc));
    assertFalse(LineContainers.isAtLineStart(doc, s.inX));
  }

  public void testEmptyLineCheck() {
    LineTestState s = new LineTestState();
    assertFalse(LineContainers.isAtEmptyLine(doc, s.afterLine));
    assertFalse(LineContainers.isAtEmptyLine(doc, s.beforeLine2));
    assertTrue(LineContainers.isAtEmptyLine(doc, s.beforeLine3));
    assertFalse(LineContainers.isAtEmptyLine(doc, s.inAbc));
    assertFalse(LineContainers.isAtEmptyLine(doc, s.inX));
  }

  public void testRounding() {
    LineTestState s = new LineTestState();

    // at node boundaries
    assertSame(s.beforeLine, LineContainers.roundLocation(
        doc, Rounding.NONE, s.beforeLine, RoundDirection.RIGHT));
    assertSame(s.afterLine, LineContainers.roundLocation(
        doc, Rounding.NONE, s.afterLine, RoundDirection.RIGHT));
    // in text
    assertSame(s.inAbc, LineContainers.roundLocation(
        doc, Rounding.NONE, s.inAbc, RoundDirection.RIGHT));
    // in a nested element, check it does not jump out
    assertSame(s.inX, LineContainers.roundLocation(
        doc, Rounding.NONE, s.inX, RoundDirection.RIGHT));

    try {
      LineContainers.roundLocation(doc, Rounding.WORD, s.afterLine, RoundDirection.RIGHT);
      fail("You forgot to write a unit test when implementing word rounding!");
    } catch (UnsupportedOperationException e) {
      // ok
    }

    try {
      LineContainers.roundLocation(doc, Rounding.SENTENCE, s.afterLine, RoundDirection.RIGHT);
      fail("You forgot to write a unit test when implementing sentence rounding!");
    } catch (UnsupportedOperationException e) {
      // ok
    }

    // just before the first line
    assertEquals(s.beforeLine, LineContainers.roundLocation(
        doc, Rounding.LINE, s.beforeLine, RoundDirection.RIGHT));
    // just after the preceding line
    assertEquals(s.beforeLine2, LineContainers.roundLocation(
        doc, Rounding.LINE, s.afterLine, RoundDirection.RIGHT));
    // in text
    assertEquals(s.beforeLine2, LineContainers.roundLocation(
        doc, Rounding.LINE, s.inAbc, RoundDirection.RIGHT));
    // *does* jump out
    assertEquals(s.beforeLine2, LineContainers.roundLocation(
        doc, Rounding.LINE, s.inX, RoundDirection.RIGHT));
    // ignore lines not direct children of the line container
    assertEquals(s.beforeLine2, LineContainers.roundLocation(
        doc, Rounding.LINE, s.beforeInvalidLine, RoundDirection.RIGHT));
    // just before a line with preceding content
    assertEquals(s.beforeLine2, LineContainers.roundLocation(
        doc, Rounding.LINE, s.beforeLine2, RoundDirection.RIGHT));
    // just before a line with an immediately preceeding line
    assertEquals(s.beforeLine3, LineContainers.roundLocation(
        doc, Rounding.LINE, s.beforeLine3, RoundDirection.RIGHT));
    // inside text at the end
    assertEquals(s.endLc, LineContainers.roundLocation(
        doc, Rounding.LINE, s.inGhi, RoundDirection.RIGHT));
    // just before the end
    assertEquals(s.endLc, LineContainers.roundLocation(
        doc, Rounding.LINE, s.endLc, RoundDirection.RIGHT));
    // outside of line container is invalid
    assertNull(LineContainers.roundLocation(
        doc, Rounding.LINE, Point.before(doc, s.lc), RoundDirection.RIGHT));
    assertNull(LineContainers.roundLocation(
        doc, Rounding.LINE, Point.after(doc, s.lc), RoundDirection.RIGHT));
    assertNull(LineContainers.roundLocation(
        doc, Rounding.LINE,
        Point.inText(s.lc.getNextSibling(), 2), RoundDirection.RIGHT));
  }

  public void testInsertLine() {
    LineTestState s;

    // at node boundaries
    s = new LineTestState();
    checkInsertLine(s.beforeLine, Rounding.NONE, s.beforeLine);
    s = new LineTestState();
    checkInsertLine(s.afterLine, Rounding.NONE, s.afterLine);
    // in text
    s = new LineTestState();
    checkInsertLine(s.inAbc, Rounding.NONE, s.inAbc);
    // in a nested element, check it *does* jump out
    s = new LineTestState();
    checkInsertLine(s.afterX, Rounding.NONE, s.inX);

    // just before the first line
    s = new LineTestState();
    checkInsertLine(s.beforeLine, Rounding.LINE, s.beforeLine);
    // just after the preceding line
    s = new LineTestState();
    checkInsertLine(s.beforeLine2, Rounding.LINE, s.afterLine);
    // in text
    s = new LineTestState();
    checkInsertLine(s.beforeLine2, Rounding.LINE, s.inAbc);
    // *does* jump out
    s = new LineTestState();
    checkInsertLine(s.beforeLine2, Rounding.LINE, s.inX);
    // ignore lines not direct children of the line container
    s = new LineTestState();
    checkInsertLine(s.beforeLine2, Rounding.LINE, s.beforeInvalidLine);
    // just before a line with preceding content
    s = new LineTestState();
    checkInsertLine(s.beforeLine2, Rounding.LINE, s.beforeLine2);
    // just before a line with an immediately preceeding line
    s = new LineTestState();
    checkInsertLine(s.beforeLine3, Rounding.LINE, s.beforeLine3);
    // inside text at the end
    s = new LineTestState();
    checkInsertLine(s.endLc, Rounding.LINE, s.inGhi);
    // just before the end
    s = new LineTestState();
    checkInsertLine(s.endLc, Rounding.LINE, s.endLc);

    // append
    s = new LineTestState();
    checkAppendLine(s.endLc, null);
    s = new LineTestState();
    checkAppendLine(s.endLc, XmlStringBuilder.createText("blah").wrap("y"));

    getDocWithoutSchema("");
    LineContainers.appendLine(doc, XmlStringBuilder.createText("blah").wrap("y"));
    assertEquals("<body><line></line><y>blah</y></body>",
        XmlStringBuilder.innerXml(doc).toString());

    getDocWithoutSchema("<x>abc</x>");
    LineContainers.appendLine(doc, XmlStringBuilder.createText("blah").wrap("y"));
    assertEquals("<x>abc</x><body><line></line><y>blah</y></body>",
        XmlStringBuilder.innerXml(doc).toString());

    // outside of line container is invalid
    try {
      s = new LineTestState();
      LineContainers.insertLine(doc, Rounding.LINE, Point.before(doc, s.lc));
      fail("Expected invalid location exception");
    } catch (IllegalArgumentException iae) {
      // ok
    }
    try {
      s = new LineTestState();
      LineContainers.insertLine(doc, Rounding.LINE, Point.after(doc, s.lc));
      fail("Expected invalid location exception");
    } catch (IllegalArgumentException iae) {
      // ok
    }
    try {
      s = new LineTestState();
      LineContainers.insertLine(doc, Rounding.LINE,
          Point.inText(s.lc.getNextSibling(), 2));
      fail("Expected invalid location exception");
    } catch (IllegalArgumentException iae) {
      // ok
    }
  }

  public void testAppendLineWithAttributes() {
    getDocWithSchema("");
    LineContainers.appendLine(doc, XmlStringBuilder.createText("hi"),
        new AttributesImpl("t", "h2"));
    assertEquals("h2", doc.getAttribute(DocHelper.getElementWithTagName(doc, "line"), "t"));

    getDocWithSchema("<body><line/>abc</body>");
    LineContainers.appendLine(doc, XmlStringBuilder.createText("hi"),
        new AttributesImpl("id", "2", "t", "h2"));
    assertEquals("h2", doc.getAttribute(DocHelper.findElementById(doc, "2"), "t"));
  }

  public void testAppendObeysSchema() {
    getDocWithSchema("");
    LineContainers.appendLine(doc, XmlStringBuilder.createText("hi"));
  }

  public void testInsertInto() {
    getDocWithSchema("<body><line/>abc</body>");
    Point<Node> afterLine = Point.after(doc, DocHelper.getElementWithTagName(doc, "line"));
    LineContainers.insertInto(doc, afterLine,
        XmlStringBuilder.createText("blah").wrap("input"));
    assertEquals("<body><line></line><input>blah</input>abc</body>",
        XmlStringBuilder.innerXml(doc).toString());

    getDocWithSchema("<body><line/>abc</body>");
    Point<Node> beforeLine = Point.before(doc, DocHelper.getElementWithTagName(doc, "line"));
    LineContainers.insertInto(doc, beforeLine,
        XmlStringBuilder.createText("blah").wrap("input"));
    assertEquals("<body><line></line><input>blah</input><line></line>abc</body>",
        XmlStringBuilder.innerXml(doc).toString());
  }

  public void testInsertContentIntoLineStart() {
    getDocWithSchema("<body><line/>abc</body>");
    LineContainers.insertContentIntoLineStart(doc, DocHelper.getElementWithTagName(doc, "line"),
        XmlStringBuilder.createText("blah").wrap("input"));
    assertEquals("<body><line></line><input>blah</input>abc</body>",
        XmlStringBuilder.innerXml(doc).toString());
  }

  public void testInsertContentIntoLineEnd() {
    getDocWithSchema("<body><line/>abc</body>");
    LineContainers.insertContentIntoLineEnd(doc, DocHelper.getElementWithTagName(doc, "line"),
        XmlStringBuilder.createText("blah").wrap("input"));
    assertEquals("<body><line></line>abc<input>blah</input></body>",
        XmlStringBuilder.innerXml(doc).toString());
  }

  public void testAppendToLastLine() {
    getDocWithSchema("<body><line/>abc</body>");
    LineContainers.appendToLastLine(doc, XmlStringBuilder.createText("blah").wrap("input"));
    assertEquals("<body><line></line>abc<input>blah</input></body>",
        XmlStringBuilder.innerXml(doc).toString());

    getDocWithoutSchema("");
    LineContainers.appendToLastLine(doc, XmlStringBuilder.createText("blah").wrap("input"));
    assertEquals("<body><line></line><input>blah</input></body>",
        XmlStringBuilder.innerXml(doc).toString());
  }

  public void testGetRelatedLineElement() {
    LineTestState s = new LineTestState();
    Element line1 = DocHelper.getElementWithTagName(doc, "line");
    Element line2 = DocHelper.findElementById(doc, "2");
    Element line3 = DocHelper.findElementById(doc, "3");

    getDocWithoutSchema("<lc><line/>abc<x>def<line id=\"bad\"/></x>."
        + "<line id=\"2\"/><line id=\"3\"/>ghi</lc>jkl");

    assertNull(LineContainers.getRelatedLineElement(doc, Point.start(doc, s.lc)));
    assertNull(LineContainers.getRelatedLineElement(doc, s.beforeLine));
    assertSame(line1, LineContainers.getRelatedLineElement(doc, s.afterLine));
    assertSame(line1, LineContainers.getRelatedLineElement(doc, s.inAbc));
    assertSame(line1, LineContainers.getRelatedLineElement(doc, s.inX));
    assertSame(line1, LineContainers.getRelatedLineElement(doc, s.afterX));
    assertSame(line1, LineContainers.getRelatedLineElement(doc, s.beforeInvalidLine));
    assertSame(line1, LineContainers.getRelatedLineElement(doc, s.beforeLine2));
    assertSame(line2, LineContainers.getRelatedLineElement(doc, s.beforeLine3));
    assertSame(line3, LineContainers.getRelatedLineElement(doc, s.inGhi));
    assertSame(line3, LineContainers.getRelatedLineElement(doc, Point.end((Node)s.lc)));
  }

  public void testGetLineRanges() {
    getDocWithSchema("");
    List<Range> ranges = LineContainers.getLineRanges(doc);
    assertEquals(0, ranges.size());

    getDocWithSchema("<body><line/></body>");
    checkLineRanges("");

    getDocWithSchema("<body><line/>abc</body>");
    checkLineRanges("abc");

    getDocWithSchema("<body><line/>abc<input/>def</body>");
    checkLineRanges("abcdef");

    getDocWithSchema("<body><line/>abc<input>_</input>def</body>");
    checkLineRanges("abc_def");

    getDocWithSchema("<body><line/>abc<line/>def</body>");
    checkLineRanges("abc", "def");

    getDocWithSchema("<body><line/>a day<line/> late and <line/>a dollar<line/> short</body>");
    checkLineRanges("a day", " late and ", "a dollar", " short");
  }

  public void testDeleteLine() {
    getDocWithSchema("<body><line/>foo</body>");
    LineContainers.deleteLine(doc, DocHelper.getElementWithTagName(doc, "line"));
    assertEquals("<body><line></line></body>", XmlStringBuilder.innerXml(doc).toString());

    getDocWithoutSchema("<body><line><x/></line>foo</body>");
    LineContainers.deleteLine(doc, DocHelper.getElementWithTagName(doc, "line"));
    assertEquals("<body><line></line></body>", XmlStringBuilder.innerXml(doc).toString());

    getDocWithSchema("<body><line/>foo<line/>bar</body>");
    LineContainers.deleteLine(doc, DocHelper.getElementWithTagName(doc, "line"));
    assertEquals("<body><line></line>bar</body>", XmlStringBuilder.innerXml(doc).toString());

    getDocWithSchema("<body><line/>foo<line id=\"2\"/>bar<line/>baz</body>");
    LineContainers.deleteLine(doc, DocHelper.findElementById(doc, "2"));
    assertEquals("<body><line></line>foo<line></line>baz</body>",
        XmlStringBuilder.innerXml(doc).toString());

    getDocWithoutSchema("<x/><body><line/>foo</body>");
    try {
      LineContainers.deleteLine(doc, DocHelper.getElementWithTagName(doc, "x"));
      fail("Did not reject non-line element");
    } catch (IllegalArgumentException e) {
      // ok
    }
    assertEquals("<x></x><body><line></line>foo</body>", XmlStringBuilder.innerXml(doc).toString());
  }

  private void checkLineRanges(String ... expectedLines) {
    List<Range> ranges = LineContainers.getLineRanges(doc);
    assertEquals(expectedLines.length, ranges.size());

    int i = 0;
    for (Range r : ranges) {
      Point<Node> start = doc.locate(r.getStart());
      Point<Node> end = doc.locate(r.getStart());
      String expectedLine = expectedLines[i++];
      assertEquals(expectedLine, DocHelper.getText(doc, doc, r.getStart(), r.getEnd()));
    }
  }

  // Delete this after 2009/09/15
  public void testRejectsParagraphs() {
    getDocWithoutSchema("<p>blah</p>");
    try {
      LineContainers.appendLine(doc, XmlStringBuilder.createText("yep"));
      fail("Did not reject paragraph doc");
    } catch (IllegalArgumentException e) {
      // ok
    }
  }

  private void checkInsertLine(Point<Node> expectedLocation,
      Rounding rounding, Point<Node> location) {
    checkInsertLineish(expectedLocation, rounding, location, false, 0);
  }

  private void checkInsertLineish(Point<Node> expectedPoint,
      Rounding rounding, Point<Node> location, boolean useParagraphs, int add) {
    int expectedLocation = doc.getLocation(expectedPoint) + add;

    Element el = LineContainers.insertLine(doc, rounding, location);

    assertTrue(LineContainers.isLineElement(doc, el));
    assertEquals(expectedLocation, doc.getLocation(el));
  }

  private void checkAppendLine(Point<Node> expectedPoint, XmlStringBuilder content) {
    checkAppendLineish(expectedPoint, content, false);
  }

  private void checkAppendLineish(Point<Node> expectedPoint, XmlStringBuilder content,
      boolean useParagraphs) {
    int expectedLocation = doc.getLocation(expectedPoint);

    Element el = LineContainers.appendLine(doc, content);

    if (content == null) {
      content = XmlStringBuilder.createEmpty();
    }

    assertTrue(LineContainers.isLineElement(doc, el));
    XmlStringBuilderDoc<Node, Element, Text> siblingContent = XmlStringBuilder.createEmpty(doc);
    for (Node n = el.getNextSibling(); n != null; n = n.getNextSibling()) {
      siblingContent.appendNode(n);
    }
    assertEquals(content, siblingContent);
    assertEquals(expectedLocation, doc.getLocation(el));
  }

  private MutableDocument<Node, Element, Text> getDocWithoutSchema(String innerXml) {
    cxt = ContextProviders.createTestPojoContext(innerXml, null, null, null,
        DocumentSchema.NO_SCHEMA_CONSTRAINTS);
    return doc = cxt.document();
  }

  private MutableDocument<Node, Element, Text> getDocWithSchema(String innerXml) {
    cxt = ContextProviders.createTestPojoContext(innerXml, null, null, null,
        new DocumentSchema() {
          @Override
          public List<String> getRequiredInitialChildren(String typeOrNull) {
            return SCHEMA.getRequiredInitialChildren(typeOrNull);
          }

          @Override
          public boolean permitsAttribute(String type, String attributeName) {
            return (type.equals("line") && attributeName.equals("id"))
                || SCHEMA.permitsAttribute(type, attributeName);
          }

          @Override
          public boolean permitsAttribute(String type, String attributeName,
              String attributeValue) {
            return (type.equals("line") && attributeName.equals("id"))
                || SCHEMA.permitsAttribute(type, attributeName, attributeValue);
          }

          @Override
          public boolean permitsChild(String parentTypeOrNull, String childType) {
            return SCHEMA.permitsChild(parentTypeOrNull, childType);
          }

          @Override
          public PermittedCharacters permittedCharacters(String typeOrNull) {
            return SCHEMA.permittedCharacters(typeOrNull);
          }
    });
    return doc = cxt.document();
  }
}
TOP

Related Classes of org.waveprotocol.wave.model.document.util.LineContainersTest$LineTestState

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.