/** * Copyright 2008 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.model.operation.wave; import org.waveprotocol.wave.model.operation.wave.BlipOperation.UpdateContributorMethod; import org.waveprotocol.wave.model.testing.ModelTestUtils; import org.waveprotocol.wave.model.wave.data.BlipData; import org.waveprotocol.wave.model.document.operation.Attributes; import org.waveprotocol.wave.model.document.operation.DocOp; import org.waveprotocol.wave.model.document.operation.impl.DocOpBuilder; import java.util.Collections; import java.util.List; /** * Tests for the shared behaviour in BlipOperation. * * @author anorth@google.com (Alex North) */ public class BlipOperationTest extends OperationTestBase { /** * A FakeBlipOperation doesn't actually modify the blip, just records * whether it's been applied. */ static class FakeBlipOperation extends BlipOperation { public boolean applied = false; protected FakeBlipOperation(WaveletOperationContext context) { super(context); } @Override protected void doApply(BlipData target) { this.applied = true; } @Override protected void doUpdate(BlipData target) { // nothing } @Override protected boolean updatesBlipMetadata(String blipId) { return false; } /** Applies and returns another FakeBlipOperation as the reverse */ @Override public List<? extends BlipOperation> applyAndReturnReverse(BlipData target) { WaveletOperationContext reverseContext = createReverseContext(target); doUpdate(target); doApply(target); return Collections.singletonList(new FakeBlipOperation(reverseContext)); } public void acceptVisitor(BlipOperationVisitor visitor) { } } private WaveletOperationContext createJaneContext() { return new WaveletOperationContext(jane, 42L, 1L); } private BlipOperation createSampleContentOperation(WaveletOperationContext context, UpdateContributorMethod method) { // Some random op that doesn't actually update the document but still "isWorthy" DocOp op = new DocOpBuilder() .retain(1) .deleteElementStart("line", Attributes.EMPTY_MAP) .deleteElementEnd() .elementStart("line", Attributes.EMPTY_MAP) .elementEnd() .retain(1) .build(); assertTrue(WorthyChangeChecker.isWorthy(op)); return new BlipContentOperation(context, op, method); } private BlipOperation createSampleContentOperation(UpdateContributorMethod method) { return createSampleContentOperation(context, method); } private BlipOperation createSampleContentOperation() { return createSampleContentOperation(UpdateContributorMethod.ADD); } public void testGetContext() { BlipOperation op = new FakeBlipOperation(context); assertEquals(op.getContext(), context); } public void testApplyInvokesSubclassDoApply() throws Exception { BlipData data = createBlipData(); FakeBlipOperation op = new FakeBlipOperation(context); op.apply(data); assertTrue(op.applied); } /** * Tests that apply() updates the blip timestamp to match the context */ public void testApplyUpdatesTimestamp() throws Exception { BlipData data = createBlipData(); BlipOperation op = createSampleContentOperation(); assertFalse(context.getTimestamp() == data.getLastModifiedTime()); op.apply(data); // The last modified time is now the context time assertEquals(context.getTimestamp(), data.getLastModifiedTime()); // The blip version is updated to match the wavelet version + 1 (but the op // doesn't actually increment the wavelet/blip version until it's applied // to a wavelet). assertEquals(waveletData.getVersion() + 1, data.getLastModifiedVersion()); } public void testNoneContributorMethodLeavesContributors() throws Exception { BlipData data = createBlipData(); BlipOperation op = createSampleContentOperation(UpdateContributorMethod.NONE); op.apply(data); assertEquals(data.getContributors(), noParticipants); } public void testAddContributorMethodAddsNewContributor() throws Exception { BlipData data = createBlipData(); BlipOperation op = createSampleContentOperation(UpdateContributorMethod.ADD); op.apply(data); assertTrue(data.getContributors().contains(fred)); op = createSampleContentOperation(createJaneContext(), UpdateContributorMethod.ADD); op.apply(data); assertTrue(data.getContributors().contains(fred)); assertTrue(data.getContributors().contains(jane)); } public void testAddContributorMethodDoesntDuplicateContributors() throws Exception { BlipData data = createBlipData(); BlipOperation op = createSampleContentOperation(UpdateContributorMethod.ADD); op.apply(data); op = createSampleContentOperation(UpdateContributorMethod.ADD); op.apply(data); assertEquals(Collections.singleton(fred), data.getContributors()); } public void testReverseAddContributorRemovesContributor() throws Exception { BlipData data = createBlipData(); BlipOperation op = createSampleContentOperation(UpdateContributorMethod.ADD); List<? extends BlipOperation> reverseOps = op.applyAndReturnReverse(data); // adds fred for (BlipOperation rop : reverseOps) { rop.apply(data); } assertEquals(noParticipants, data.getContributors()); } private BlipData createBlipData() { return waveletData.createDocument("blipid", fred, noParticipants, ModelTestUtils.createContent(""), 0L, 0L); } }