// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed 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 com.google.collide.shared.document;
import static com.google.collide.shared.document.AnchorTestUtils.assertAnchorColumns;
import static com.google.collide.shared.document.AnchorTestUtils.assertAnchorLineNumbers;
import static com.google.collide.shared.document.AnchorTestUtils.assertAnchorPositions;
import static com.google.collide.shared.document.anchor.AnchorManager.IGNORE_COLUMN;
import static com.google.collide.shared.document.anchor.AnchorManager.IGNORE_LINE_NUMBER;
import static com.google.collide.shared.document.anchor.InsertionPlacementStrategy.EARLIER;
import static com.google.collide.shared.document.anchor.InsertionPlacementStrategy.LATER;
import com.google.collide.json.shared.JsonArray;
import com.google.collide.shared.document.anchor.Anchor;
import com.google.collide.shared.document.anchor.Anchor.RemovalStrategy;
import com.google.collide.shared.document.anchor.AnchorList;
import com.google.collide.shared.document.anchor.AnchorManager;
import com.google.collide.shared.document.anchor.AnchorType;
import com.google.collide.shared.document.anchor.InsertionPlacementStrategy;
import com.google.common.base.Joiner;
import junit.framework.TestCase;
import java.util.ArrayList;
/**
*/
public class AnchorTests extends TestCase {
// 100 cols FTW
private static final String[] LINES = {"About Google\n",
"\n",
"The Beginning\n",
"\n",
"Beginning in 1996, Stanford University graduate students Larry Page and "
+ "Sergey Brin built a\n",
"search engine called 'BackRub' that used links to determine the importance of "
+ "individual\n",
"web pages. By 1998 they had formalized their work, creating the company you know "
+ "today as Google."};
private Document doc;
private AnchorManager anchorManager;
private static final AnchorType ANCHOR_TYPE_1 = AnchorType.create(AnchorTests.class, "1");
private static final AnchorType ANCHOR_TYPE_2 = AnchorType.create(AnchorTests.class, "2");
private Anchor docStart;
private Anchor docStartCol1;
private Anchor firstEmptyLine;
private Anchor theBeginning;
private Anchor year1996a;
private Anchor year1996b;
private Anchor year1996c;
private Anchor individual;
private Anchor year1998;
private Anchor docEnd;
private ArrayList<Anchor> anchors;
@Override
protected void setUp() {
doc =
Document.createFromString(Joiner.on("").join(LINES));
anchorManager = doc.getAnchorManager();
Line line = doc.getFirstLine();
docStart = anchorManager.createAnchor(ANCHOR_TYPE_1, line, IGNORE_LINE_NUMBER, 0);
docStartCol1 = anchorManager.createAnchor(ANCHOR_TYPE_1, line, 0, 1);
line = line.getNextLine();
firstEmptyLine = anchorManager.createAnchor(ANCHOR_TYPE_1, line, IGNORE_LINE_NUMBER, 0);
line = line.getNextLine();
theBeginning = anchorManager.createAnchor(ANCHOR_TYPE_2, line, IGNORE_LINE_NUMBER, 0);
line = line.getNextLine().getNextLine();
year1996a = anchorManager.createAnchor(ANCHOR_TYPE_1, line, IGNORE_LINE_NUMBER, 13);
year1996b = anchorManager.createAnchor(ANCHOR_TYPE_2, line, IGNORE_LINE_NUMBER, 13);
year1996c = anchorManager.createAnchor(ANCHOR_TYPE_2, line, IGNORE_LINE_NUMBER, 13);
line = line.getNextLine();
individual = anchorManager.createAnchor(ANCHOR_TYPE_1, line, IGNORE_LINE_NUMBER, 79);
line = line.getNextLine();
year1998 = anchorManager.createAnchor(ANCHOR_TYPE_2, line, IGNORE_LINE_NUMBER, 19);
docEnd = anchorManager.createAnchor(ANCHOR_TYPE_1, line, IGNORE_LINE_NUMBER, 99);
anchors = new ArrayList<Anchor>();
anchors.add(docStart);
anchors.add(docStartCol1);
anchors.add(firstEmptyLine);
anchors.add(theBeginning);
anchors.add(year1996a);
anchors.add(year1996b);
anchors.add(year1996c);
anchors.add(individual);
anchors.add(year1998);
anchors.add(docEnd);
}
/**
* Currently the AnchorType.create will create a new instance of an anchor for
* the same type. So, anchor types cannot rely on reference equality. If we
* ever decide to change that, this test will let us know to update
* expectations elsewhere.
*/
public void testAnchorTypeEquality() {
AnchorType type1dup = AnchorType.create(AnchorTests.class, "1");
assertEquals(ANCHOR_TYPE_1, type1dup);
assertEquals(ANCHOR_TYPE_1.toString(), type1dup.toString());
// Reminder to update AnchorType comparisons to identity rather than .equals
assertNotSame(ANCHOR_TYPE_1, type1dup);
}
/**
* Verify we can walk the anchors in order.
*/
public void testSimpleTraversal() {
AnchorList anchorList = anchorManager.getAnchors(doc.getFirstLine());
assertEquals(2, anchorList.size());
Anchor anchor = anchorList.get(0);
for (Anchor a : anchors) {
assertSame(anchor, a);
anchor = anchorManager.getNextAnchor(anchor);
}
}
/**
* Verify we can walk the anchors in reverse order
*/
public void testBackwardsTraversal() {
AnchorList anchorList = anchorManager.getAnchors(doc.getLastLine());
assertEquals(2, anchorList.size());
Anchor anchor = docEnd;
for (int i = anchors.size() - 1; i >= 0; i--) {
assertSame(anchors.get(i), anchor);
assertEquals(anchors.get(i).getType(), anchor.getType());
anchor = anchorManager.getPreviousAnchor(anchor);
}
}
/**
* Test {@link AnchorManager#getAnchorsByTypeOrNull(Line, AnchorType)}.
*/
public void testGetAnchorsByTypeOrNull() {
Line line = doc.getFirstLine();
JsonArray<Anchor> anchors =
AnchorManager.getAnchorsByTypeOrNull(line, ANCHOR_TYPE_1);
assertEquals(2, anchors.size());
assertSame(docStart, anchors.get(0));
assertSame(docStartCol1, anchors.get(1));
anchors = AnchorManager.getAnchorsByTypeOrNull(line, ANCHOR_TYPE_2);
assertEquals(0, anchors.size());
line = line.getNextLine();
anchors = AnchorManager.getAnchorsByTypeOrNull(line, ANCHOR_TYPE_1);
assertEquals(1, anchors.size());
assertSame(firstEmptyLine, anchors.get(0));
anchors = AnchorManager.getAnchorsByTypeOrNull(line, ANCHOR_TYPE_2);
assertEquals(0, anchors.size());
line = line.getNextLine();
anchors = AnchorManager.getAnchorsByTypeOrNull(line, ANCHOR_TYPE_1);
assertEquals(0, anchors.size());
anchors = AnchorManager.getAnchorsByTypeOrNull(line, ANCHOR_TYPE_2);
assertEquals(1, anchors.size());
assertSame(theBeginning, anchors.get(0));
line = line.getNextLine();
assertNotNull(line);
anchors = AnchorManager.getAnchorsByTypeOrNull(line, ANCHOR_TYPE_1);
assertNull(anchors);
anchors = AnchorManager.getAnchorsByTypeOrNull(line, ANCHOR_TYPE_2);
assertNull(anchors);
}
/**
* Currently, we rely on being able to push anchors past the end of the line.
*/
public void testAnchorPastEnd() {
Line line = doc.getFirstLine().getNextLine();
Anchor anchor = anchorManager.createAnchor(ANCHOR_TYPE_1, line, IGNORE_LINE_NUMBER, 1);
assertSame(anchorManager.getPreviousAnchor(anchor), firstEmptyLine);
line = line.getNextLine();
anchorManager.moveAnchor(anchor, line, IGNORE_LINE_NUMBER, 100);
assertSame(anchorManager.getPreviousAnchor(anchor), theBeginning);
}
/**
* Verify that the type filter is working as expected.
*/
public void testType1Traversal() {
ArrayList<Anchor> type1Anchors = new ArrayList<Anchor>();
for (Anchor a : anchors) {
if (a.getType().equals(ANCHOR_TYPE_1)) {
type1Anchors.add(a);
}
}
Anchor anchor = docStart;
assertEquals(ANCHOR_TYPE_1, anchor.getType());
for (Anchor a : type1Anchors) {
assertSame(a, anchor);
assertEquals(ANCHOR_TYPE_1, anchor.getType());
anchor = anchorManager.getNextAnchor(anchor, ANCHOR_TYPE_1);
}
assertNull(anchor);
}
public void testInsertionPlacementStrategyForLineAnchors() {
Anchor a1 =
createAnchorForPlacementStrategy(doc.getFirstLine(), true, IGNORE_COLUMN, EARLIER);
Anchor a2 =
createAnchorForPlacementStrategy(doc.getFirstLine(), true, IGNORE_COLUMN, LATER);
assertAnchorLineNumbers(a1, 0, a2, 0);
doc.insertText(doc.getFirstLine(), 0, "Newline\n");
assertAnchorLineNumbers(a1, 0, a2, 1);
doc.deleteText(doc.getFirstLine(), 0, doc.getFirstLine().getText().length());
assertAnchorLineNumbers(a1, 0, a2, 0);
doc.insertText(doc.getFirstLine(), 0, "Many\nnew\nlines\n!\n");
assertAnchorLineNumbers(a1, 0, a2, 4);
}
public void testInsertionPlacementStrategyForColumnAnchors() {
Anchor a1 = createAnchorForPlacementStrategy(doc.getFirstLine(), false, 0, EARLIER);
Anchor a2 = createAnchorForPlacementStrategy(doc.getFirstLine(), false, 0, LATER);
assertAnchorColumns(a1, 0, a2, 0);
doc.insertText(doc.getFirstLine(), 0, "a");
assertAnchorColumns(a1, 0, a2, 1);
doc.deleteText(doc.getFirstLine(), 0, doc.getFirstLine().getText().length());
assertAnchorColumns(a1, 0, a2, 0);
doc.insertText(doc.getFirstLine(), 0, "more than a trivial insertion");
assertAnchorColumns(a1, 0, a2, "more than a trivial insertion".length());
doc.insertText(doc.getFirstLine(), 0, "\n");
assertEquals(doc.getFirstLine(), a1.getLine());
assertEquals(doc.getFirstLine().getNextLine(), a2.getLine());
assertAnchorColumns(a1, 0, a2, "more than a trivial insertion".length());
}
public void testInsertionPlacementStrategyForLineNumberAndColumnAnchors() {
Anchor a1 = createAnchorForPlacementStrategy(doc.getFirstLine(), true, 1, EARLIER);
Anchor a2 = createAnchorForPlacementStrategy(doc.getFirstLine(), true, 1, LATER);
assertAnchorPositions(a1, 0, 1, a2, 0, 1);
doc.insertText(doc.getFirstLine(), 0, "a");
assertAnchorPositions(a1, 0, 2, a2, 0, 2);
doc.insertText(doc.getFirstLine(), 2, "a");
assertAnchorPositions(a1, 0, 2, a2, 0, 3);
doc.insertText(doc.getFirstLine(), 0, "\n");
assertAnchorPositions(a1, 1, 2, a2, 1, 3);
Line secondLine = doc.getFirstLine().getNextLine();
doc.deleteText(secondLine, 0, secondLine.getText().length());
assertAnchorPositions(a1, 1, 0, a2, 1, 0);
doc.insertText(secondLine, 0, "more than a trivial insertion");
assertAnchorPositions(a1, 1, 0, a2, 1, "more than a trivial insertion".length());
doc.insertText(secondLine, 0, "many\nnew\nlines\n!\n");
assertAnchorPositions(a1, 1, 0, a2, 5, "more than a trivial insertion".length());
}
private Anchor createAnchorForPlacementStrategy(Line line, boolean storeLineNumber, int column,
InsertionPlacementStrategy insertionPlacementStrategy) {
Anchor a =
doc.getAnchorManager().createAnchor(ANCHOR_TYPE_1, doc.getFirstLine(),
storeLineNumber ? doc.getLineFinder().findLine(line).number() : IGNORE_LINE_NUMBER,
column);
a.setInsertionPlacementStrategy(insertionPlacementStrategy);
a.setRemovalStrategy(RemovalStrategy.SHIFT);
return a;
}
}