/** * Copyright 2009 Google Inc. * * 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 org.waveprotocol.wave.client.doodad.selection; import static org.mockito.Mockito.atMost; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.waveprotocol.wave.client.doodad.selection.SelectionAnnotationHandler.STALE_CARET_TIMEOUT_MS; import static org.waveprotocol.wave.model.document.util.DocCompare.ATTRS; import static org.waveprotocol.wave.model.document.util.DocCompare.STRUCTURE; import junit.framework.TestCase; import org.waveprotocol.wave.client.account.impl.ProfileImpl; import org.waveprotocol.wave.client.account.impl.ProfileManagerImpl; import org.waveprotocol.wave.client.doodad.selection.SelectionAnnotationHandler.CaretViewFactory; import org.waveprotocol.wave.client.editor.ElementHandlerRegistry; import org.waveprotocol.wave.client.editor.content.AnnotationPainter; import org.waveprotocol.wave.client.editor.content.PainterRegistry; import org.waveprotocol.wave.client.editor.content.PainterRegistryImpl; import org.waveprotocol.wave.client.editor.content.Registries; import org.waveprotocol.wave.client.editor.content.RegistriesImpl; import org.waveprotocol.wave.client.scheduler.testing.FakeTimerService; import org.waveprotocol.wave.model.document.Doc; import org.waveprotocol.wave.model.document.operation.automaton.DocumentSchema; 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.AnnotationRegistry; import org.waveprotocol.wave.model.document.util.AnnotationRegistryImpl; import org.waveprotocol.wave.model.document.util.ContextProviders; import org.waveprotocol.wave.model.document.util.ContextProviders.TestDocumentContext; import org.waveprotocol.wave.model.document.util.DocCompare; import org.waveprotocol.wave.model.document.util.FocusedRange; import org.waveprotocol.wave.model.wave.ParticipantId; import java.util.HashMap; import java.util.Map; /** * Tests for {@link SelectionAnnotationHandler}. * * @author danilatos@google.com (Daniel Danilatos) */ public class SelectionAnnotationHandlerTest extends TestCase { public static class FakeCaretViewFactory implements CaretViewFactory { private final Map<CaretView, Object> markers = new HashMap<CaretView, Object>(); private final Object dummy = new Object(); @Override public CaretView createMarker() { CaretView marker = mock(CaretView.class); markers.put(marker, dummy); return marker; } @Override public void setMarker(Object element, CaretView marker) { assertTrue(markers.containsKey(marker)); markers.put(marker, element); } public boolean isAttached(CaretView marker) { return markers.get(marker) instanceof Doc.E; } } /** Session for the current editor. */ class FakeSession { final String id; final ProfileImpl profile; final SelectionExtractor extractor; String displayName; public FakeSession(String name) { profile = profileManager.getProfile(ParticipantId.ofUnsafe(name + "@example.com")); id = "#" + name + "#"; extractor = new SelectionExtractor(handlerTimer, profile.getAddress(), id); displayName = profile.getFirstName(); } void setName(String newName) { profile.update(newName, null, null); } } ProfileManagerImpl profileManager = new ProfileManagerImpl(); AnnotationRegistry annotationRegistry = new AnnotationRegistryImpl(); FakeTimerService painterTimer = new FakeTimerService(); FakeTimerService handlerTimer = new FakeTimerService(); { handlerTimer.setStartTime(painterTimer.currentTimeMillis()); } PainterRegistry painterRegistry = new PainterRegistryImpl("s", "b", new AnnotationPainter(painterTimer)); FakeSession me = new FakeSession("me"); FakeSession me2 = new FakeSession("me2"); FakeSession joe = new FakeSession("joe"); FakeCaretViewFactory markerFactory = new FakeCaretViewFactory(); TestDocumentContext<Node, Element, Text> cxt; private SelectionAnnotationHandler handler; @Override protected void setUp() { Registries registries = new RegistriesImpl(mock(ElementHandlerRegistry.class), annotationRegistry, painterRegistry); handler = SelectionAnnotationHandler.register( registries, handlerTimer, markerFactory, me.id, profileManager); String content = "abcdefghij"; cxt = ContextProviders.createTestPojoContext2( content, null, annotationRegistry, null, DocumentSchema.NO_SCHEMA_CONSTRAINTS); AnnotationPainter.createAndSetDocPainter(cxt, painterRegistry); } public void testBehaviour() { // Ignore own cursor me.extractor.writeSelection( cxt.document(), new FocusedRange(2, 4), "wo", handlerTimer.currentTimeMillis()); assertTrue(markerFactory.markers.isEmpty()); check("abcdefghij"); joe.extractor.writeSelection( cxt.document(), new FocusedRange(1, 3), "ni", handlerTimer.currentTimeMillis()); assertFalse(markerFactory.markers.isEmpty()); CaretView joeUi = handler.getUiForSession(joe.id); verify(joeUi).setName("Joe"); verify(joeUi).setCompositionState("ni"); assertFalse(markerFactory.isAttached(joeUi)); painterTimer.tick(10); assertTrue(markerFactory.isAttached(joeUi)); check("a<s>bc</s><b/>defghij"); joe.setName("Jimbo"); verify(joeUi).setName("Jimbo"); assertEquals(2, painterRegistry.getKeys().countEntries()); handlerTimer.tick(STALE_CARET_TIMEOUT_MS / 2); joe.setName("Jimbo2"); verify(joeUi, atMost(1)).setName("Jimbo2"); // check cleanup after timeout handlerTimer.tick(STALE_CARET_TIMEOUT_MS); joe.setName("Jimbo3"); verify(joeUi, never()).setName("Jimbo3"); assertEquals(0, painterRegistry.getKeys().countEntries()); joe.extractor.writeSelection( cxt.document(), new FocusedRange(2, 4), "ni", handlerTimer.currentTimeMillis()); handlerTimer.tick(STALE_CARET_TIMEOUT_MS - 1); painterTimer.tick(10); joe.setName("Jimbo4"); verify(joeUi).setName("Jimbo4"); joe.extractor.writeSelection( cxt.document(), new FocusedRange(2, 4), "ni", handlerTimer.currentTimeMillis()); handlerTimer.tick(STALE_CARET_TIMEOUT_MS - 1); painterTimer.tick(10); joe.setName("Jimbo5"); verify(joeUi).setName("Jimbo5"); } private void check(String xml) { assertTrue(DocCompare.equivalent(STRUCTURE - ATTRS, xml.replaceAll("<b/>", "<b><" + CaretMarkerRenderer.FULL_TAGNAME + "/></b>"), cxt.annotatableContent())); } }