/** * 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.testing; import org.waveprotocol.wave.model.document.operation.DocOp; import org.waveprotocol.wave.model.document.operation.impl.DocOpBuilder; import org.waveprotocol.wave.model.operation.wave.AddParticipant; import org.waveprotocol.wave.model.operation.wave.BlipContentOperation; import org.waveprotocol.wave.model.operation.wave.NoOp; import org.waveprotocol.wave.model.operation.wave.RemoveParticipant; import org.waveprotocol.wave.model.operation.wave.TransformedWaveletDelta; import org.waveprotocol.wave.model.operation.wave.WaveletBlipOperation; import org.waveprotocol.wave.model.operation.wave.WaveletDelta; import org.waveprotocol.wave.model.operation.wave.WaveletOperation; import org.waveprotocol.wave.model.operation.wave.WaveletOperationContext; import org.waveprotocol.wave.model.util.CollectionUtils; import org.waveprotocol.wave.model.version.HashedVersion; import org.waveprotocol.wave.model.wave.Constants; import org.waveprotocol.wave.model.wave.ParticipantId; import java.util.Arrays; import java.util.List; import java.util.Random; /** * A bunch of utility functions to make testing easier. * * @author zdwang@google.com (David Wang) */ public class DeltaTestUtil { private static final WaveletOperationContext DUMMY = new WaveletOperationContext(null, 0L, 0L); private final ParticipantId author; private final Random random = new Random(42); /** * Creates a {@link DeltaTestUtil} with which operations authored by the given * author can readily be made. */ public DeltaTestUtil(String author) { this(new ParticipantId(author)); } /** * Creates a {@link DeltaTestUtil} with which operations authored by the given * author can readily be made. */ public DeltaTestUtil(ParticipantId author) { this.author = author; } public ParticipantId getAuthor() { return author; } /** * Creates an XmlDelete with the given data. */ public WaveletOperation delete(int posStart, String characters, int remaining) { DocOp op = new DocOpBuilder() .retain(posStart) .deleteCharacters(characters) .retain(remaining) .build(); BlipContentOperation blipOp = new BlipContentOperation( new WaveletOperationContext(author, 0L, 1), op); WaveletBlipOperation waveOp = new WaveletBlipOperation("blip id", blipOp); return waveOp; } /** * Wrap an op with a delta. */ public TransformedWaveletDelta delta(long targetVersion, WaveletOperation op) { return TransformedWaveletDelta.cloneOperations(author, HashedVersion.unsigned(targetVersion + 1), 0L, Arrays.asList(op)); } /** * Create a delta with a single NoOp operation. * * @param initialVersion The version before the operation. */ public TransformedWaveletDelta noOpDelta(long initialVersion) { return makeTransformedDelta(0L, HashedVersion.unsigned(initialVersion + 1), 1); } /** Create a NoOp operation. */ public NoOp noOp() { return new NoOp(new WaveletOperationContext(author, 0L, 1L)); } /** Create an AddParticipant operation. */ public AddParticipant addParticipant(ParticipantId participant) { return new AddParticipant(new WaveletOperationContext(author, 0L, 1L), participant); } /** Creates a RemoveParticipant operation. */ public RemoveParticipant removeParticipant(ParticipantId participant) { return new RemoveParticipant(new WaveletOperationContext(author, 0L, 1L), participant); } /** * A docop that is empty. i.e. does nothing to the document. The document must * also be empty, otherwise the operation is invalid. */ public WaveletOperation noOpDocOp(String blipId) { WaveletOperationContext context = new WaveletOperationContext(author, 0L, 1L); BlipContentOperation blipOp = new BlipContentOperation(context, (new DocOpBuilder()).build()); return new WaveletBlipOperation(blipId, blipOp); } /** * Creates an XmlInsert with the given data. */ public WaveletOperation insert(int pos, String text, int remaining, HashedVersion resultingVersion) { DocOpBuilder builder = new DocOpBuilder(); builder.retain(pos).characters(text); if (remaining > 0) { builder.retain(remaining); } BlipContentOperation blipOp = new BlipContentOperation( new WaveletOperationContext(author, 0L, 1, resultingVersion), builder.build()); WaveletBlipOperation waveOp = new WaveletBlipOperation("blip id", blipOp); return waveOp; } /** * Builds a random client delta. */ public WaveletDelta makeDelta(HashedVersion targetVersion, long timestamp, int numOps) { List<WaveletOperation> ops = CollectionUtils.newArrayList(); WaveletOperationContext context = new WaveletOperationContext(author, Constants.NO_TIMESTAMP, 1); for (int i = 0; i < numOps; ++i) { ops.add(randomOp(context)); } return new WaveletDelta(author, targetVersion, ops); } /** * Builds a no-op client delta. */ public WaveletDelta makeNoOpDelta(HashedVersion targetVersion, long timestamp, int numOps) { List<WaveletOperation> ops = CollectionUtils.newArrayList(); WaveletOperationContext context = new WaveletOperationContext(author, Constants.NO_TIMESTAMP, 1); for (int i = 0; i < numOps; ++i) { ops.add(new NoOp(context)); } return new WaveletDelta(author, targetVersion, ops); } /** * Builds a random transformed delta. */ public TransformedWaveletDelta makeTransformedDelta(long applicationTimestamp, HashedVersion resultingVersion, int numOps) { List<WaveletOperation> ops = CollectionUtils.newArrayList(); for (int i = 0; i < numOps; ++i) { ops.add(randomOp(DUMMY)); } return TransformedWaveletDelta.cloneOperations(author, resultingVersion, applicationTimestamp, ops); } /** * Creates a random op. The result is unlikely to be applicable to any * wavelet, but is generated such that we are fairly certain that it will be * unique so we can identify it when it completes a round-trip. */ private WaveletOperation randomOp(WaveletOperationContext context) { DocOp blipOp = new DocOpBuilder() .retain(Math.abs(random.nextInt()) / 2 + 1) .characters("createRndOp#" + random.nextInt()) .build(); return new WaveletBlipOperation("createRndId#" + random.nextInt(), new BlipContentOperation(context, blipOp)); } }