http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/70f39328/test/org/waveprotocol/wave/client/testing/public/static/images/unknown.jpg ---------------------------------------------------------------------- diff --git a/test/org/waveprotocol/wave/client/testing/public/static/images/unknown.jpg b/test/org/waveprotocol/wave/client/testing/public/static/images/unknown.jpg new file mode 100644 index 0000000..0f39513 Binary files /dev/null and b/test/org/waveprotocol/wave/client/testing/public/static/images/unknown.jpg differ
http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/70f39328/test/org/waveprotocol/wave/concurrencycontrol/testing/CcTestingUtils.java ---------------------------------------------------------------------- diff --git a/test/org/waveprotocol/wave/concurrencycontrol/testing/CcTestingUtils.java b/test/org/waveprotocol/wave/concurrencycontrol/testing/CcTestingUtils.java new file mode 100644 index 0000000..87617ad --- /dev/null +++ b/test/org/waveprotocol/wave/concurrencycontrol/testing/CcTestingUtils.java @@ -0,0 +1,39 @@ +/** + * 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.concurrencycontrol.testing; + +import org.waveprotocol.wave.model.operation.wave.WaveletDelta; +import org.waveprotocol.wave.model.util.ValueUtils; + +public class CcTestingUtils { + // for testing only -- not overriding .equals() because I don't want to override .hashCode() + public static boolean deltasAreEqual(WaveletDelta delta1, WaveletDelta delta2) { + if (delta1 == delta2) return true; + if (delta1 == null || delta2 == null) return false; + if (delta1.size() != delta2.size()) return false; + if (!ValueUtils.equal(delta1.getTargetVersion(), delta2.getTargetVersion())) return false; + for (int i = 0; i < delta1.size(); ++i) { + if (!delta1.get(i).equals(delta2.get(i))) { + return false; + } + } + return true; + } +} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/70f39328/test/org/waveprotocol/wave/concurrencycontrol/testing/FakeClock.java ---------------------------------------------------------------------- diff --git a/test/org/waveprotocol/wave/concurrencycontrol/testing/FakeClock.java b/test/org/waveprotocol/wave/concurrencycontrol/testing/FakeClock.java new file mode 100644 index 0000000..36d96bb --- /dev/null +++ b/test/org/waveprotocol/wave/concurrencycontrol/testing/FakeClock.java @@ -0,0 +1,39 @@ +/** + * 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.concurrencycontrol.testing; + +import org.waveprotocol.wave.concurrencycontrol.common.Clock; + +public class FakeClock implements Clock { + long currentTime; + + public FakeClock(long currentTime) { + this.currentTime = currentTime; + } + + public void setCurrentTime(long currentTime) { + this.currentTime = currentTime; + } + + @Override + public long getCurrentTime() { + return currentTime; + } +} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/70f39328/test/org/waveprotocol/wave/concurrencycontrol/testing/FakeOperationChannel.java ---------------------------------------------------------------------- diff --git a/test/org/waveprotocol/wave/concurrencycontrol/testing/FakeOperationChannel.java b/test/org/waveprotocol/wave/concurrencycontrol/testing/FakeOperationChannel.java new file mode 100644 index 0000000..babe627 --- /dev/null +++ b/test/org/waveprotocol/wave/concurrencycontrol/testing/FakeOperationChannel.java @@ -0,0 +1,67 @@ +/** + * 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.concurrencycontrol.testing; + +import org.waveprotocol.wave.concurrencycontrol.channel.OperationChannel; +import org.waveprotocol.wave.model.operation.wave.WaveletOperation; +import org.waveprotocol.wave.model.version.HashedVersion; + +import java.util.List; + + +/** + * A minimal fake operation channel. + * + * @author [email protected] (David Wang) + */ +public class FakeOperationChannel implements OperationChannel { + + @Override + public String getDebugString() { + throw new UnsupportedOperationException(); + } + + @Override + public List<HashedVersion> getReconnectVersions() { + throw new UnsupportedOperationException(); + } + + @Override + public WaveletOperation peek() { + // Does nothing + return null; + } + + @Override + public WaveletOperation receive() { + // Does nothing + return null; + } + + @Override + public void send(WaveletOperation... operations) { + // Does nothing + } + + @Override + public void setListener(Listener listener) { + // Does nothing + } +} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/70f39328/test/org/waveprotocol/wave/concurrencycontrol/testing/FakeOperationChannelMultiplexer.java ---------------------------------------------------------------------- diff --git a/test/org/waveprotocol/wave/concurrencycontrol/testing/FakeOperationChannelMultiplexer.java b/test/org/waveprotocol/wave/concurrencycontrol/testing/FakeOperationChannelMultiplexer.java new file mode 100644 index 0000000..1b0e398 --- /dev/null +++ b/test/org/waveprotocol/wave/concurrencycontrol/testing/FakeOperationChannelMultiplexer.java @@ -0,0 +1,70 @@ +/** + * 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.concurrencycontrol.testing; + +import org.waveprotocol.wave.concurrencycontrol.channel.OperationChannelMultiplexer; + +import org.waveprotocol.wave.model.id.IdFilter; +import org.waveprotocol.wave.model.id.WaveletId; +import org.waveprotocol.wave.model.util.Preconditions; + +import java.util.Collection; + +/** + * A minimal fake multiplexer. + * + * @author [email protected] (David Wang) + */ +public class FakeOperationChannelMultiplexer implements OperationChannelMultiplexer { + + @Override + public void close() { + // Does nothing + } + + @Override + public void createOperationChannel(WaveletId waveletId, + org.waveprotocol.wave.model.wave.ParticipantId creator) { + throw new UnsupportedOperationException(); + } + + @Override + public void open(Listener muxListener, IdFilter waveletFilter, + Collection<KnownWavelet> knownWavelets) { + if (!knownWavelets.isEmpty()) { + for (final KnownWavelet knownWavelet : knownWavelets) { + Preconditions.checkNotNull(knownWavelet.snapshot, + "Snapshot has no wavelet"); + Preconditions.checkNotNull(knownWavelet.committedVersion, + "Known wavelet has null committed version"); + + + muxListener.onOperationChannelCreated(new FakeOperationChannel(), + knownWavelet.snapshot, knownWavelet.accessibility); + } + // consider the wave as if open has finished. + muxListener.onOpenFinished(); + } + } + + @Override + public void open(Listener muxListener, IdFilter waveletFilter) { + } +} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/70f39328/test/org/waveprotocol/wave/concurrencycontrol/testing/FakeWaveViewServiceUpdate.java ---------------------------------------------------------------------- diff --git a/test/org/waveprotocol/wave/concurrencycontrol/testing/FakeWaveViewServiceUpdate.java b/test/org/waveprotocol/wave/concurrencycontrol/testing/FakeWaveViewServiceUpdate.java new file mode 100755 index 0000000..bc50103 --- /dev/null +++ b/test/org/waveprotocol/wave/concurrencycontrol/testing/FakeWaveViewServiceUpdate.java @@ -0,0 +1,113 @@ +/** + * 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.concurrencycontrol.testing; + +import org.waveprotocol.wave.concurrencycontrol.channel.WaveViewService; +import org.waveprotocol.wave.model.id.WaveId; +import org.waveprotocol.wave.model.id.WaveletId; +import org.waveprotocol.wave.model.operation.wave.TransformedWaveletDelta; +import org.waveprotocol.wave.model.schema.SchemaCollection; +import org.waveprotocol.wave.model.schema.SchemaProvider; +import org.waveprotocol.wave.model.util.CollectionUtils; +import org.waveprotocol.wave.model.version.HashedVersion; +import org.waveprotocol.wave.model.wave.ParticipantId; +import org.waveprotocol.wave.model.wave.data.ObservableWaveletData; +import org.waveprotocol.wave.model.wave.data.impl.EmptyWaveletSnapshot; +import org.waveprotocol.wave.model.wave.data.impl.ObservablePluggableMutableDocument; +import org.waveprotocol.wave.model.wave.data.impl.WaveletDataImpl; + +import java.util.ArrayList; +import java.util.List; + +/** + * Fake WaveViewServiceUpdate implementation for providing canned responses. + * + */ +public class FakeWaveViewServiceUpdate implements WaveViewService.WaveViewServiceUpdate { + private final SchemaProvider schemas = SchemaCollection.empty(); + private final WaveletDataImpl.Factory dataFactory = + WaveletDataImpl.Factory.create(ObservablePluggableMutableDocument.createFactory(schemas)); + + public String channelId; + public WaveletId waveletId; + public HashedVersion lastCommittedVersion; + public HashedVersion currentVersion; + public ObservableWaveletData waveletSnapshot; + public ArrayList<TransformedWaveletDelta> deltaList = CollectionUtils.newArrayList(); + public Boolean marker; + + public FakeWaveViewServiceUpdate setChannelId(String channelId) { + this.channelId = channelId; + return this; + } + + public FakeWaveViewServiceUpdate setWaveletId(WaveletId waveletId) { + this.waveletId = waveletId; + return this; + } + + public FakeWaveViewServiceUpdate setLastCommittedVersion(HashedVersion lastCommittedVersion) { + this.lastCommittedVersion = lastCommittedVersion; + return this; + } + + public FakeWaveViewServiceUpdate setCurrentVersion(HashedVersion currentVersion) { + this.currentVersion = currentVersion; + return this; + } + + public FakeWaveViewServiceUpdate setWaveletSnapshot(WaveId waveId, ParticipantId creator, + long creationTime, final HashedVersion hashedVersion) { + assert hasWaveletId(); + waveletSnapshot = dataFactory.create(new EmptyWaveletSnapshot(waveId, waveletId, creator, + hashedVersion, creationTime)); + return this; + } + + public FakeWaveViewServiceUpdate addDelta(TransformedWaveletDelta delta) { + deltaList.add(delta); + return this; + } + + public FakeWaveViewServiceUpdate setMarker(Boolean marker) { + this.marker = marker; + return this; + } + + @Override public boolean hasChannelId() { return channelId != null; } + @Override public String getChannelId() { return channelId; } + + @Override public boolean hasWaveletId() { return waveletId != null; } + @Override public WaveletId getWaveletId() { return waveletId; } + + @Override public boolean hasLastCommittedVersion() { return lastCommittedVersion != null; } + @Override public HashedVersion getLastCommittedVersion() { return lastCommittedVersion; } + + @Override public boolean hasCurrentVersion() { return currentVersion != null; } + @Override public HashedVersion getCurrentVersion() { return currentVersion; } + + @Override public boolean hasWaveletSnapshot() { return waveletSnapshot != null; } + @Override public ObservableWaveletData getWaveletSnapshot() { return waveletSnapshot; } + + @Override public boolean hasDeltas() { return !deltaList.isEmpty(); } + @Override public List<TransformedWaveletDelta> getDeltaList() { return deltaList; } + + @Override public boolean hasMarker() { return marker != null; } +} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/70f39328/test/org/waveprotocol/wave/concurrencycontrol/testing/MockOperationChannel.java ---------------------------------------------------------------------- diff --git a/test/org/waveprotocol/wave/concurrencycontrol/testing/MockOperationChannel.java b/test/org/waveprotocol/wave/concurrencycontrol/testing/MockOperationChannel.java new file mode 100644 index 0000000..67a048c --- /dev/null +++ b/test/org/waveprotocol/wave/concurrencycontrol/testing/MockOperationChannel.java @@ -0,0 +1,110 @@ +/** + * 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.concurrencycontrol.testing; + +import junit.framework.Assert; + +import org.waveprotocol.wave.concurrencycontrol.channel.OperationChannel; +import org.waveprotocol.wave.model.operation.wave.WaveletOperation; +import org.waveprotocol.wave.model.version.HashedVersion; + +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +/** + * A mock operation channel which allows expectations to be set. + * + * @author [email protected] (Alex North) + */ +public final class MockOperationChannel implements OperationChannel { + + private static enum Method { + SEND, RECEIVE, PEEK + } + + private final Queue<Object[]> expectations = new LinkedList<Object[]>(); + + /** + * Expects a call to send() with a list of operations. + */ + public void expectSend(WaveletOperation... operations) { + expectations.add(new Object[] {Method.SEND, operations}); + } + + /** + * Expects a call to receive(), which will return the provided operation (may + * be null). + */ + public void expectReceive(WaveletOperation op) { + expectations.add(new Object[] {Method.RECEIVE, op}); + } + + /** + * Expects a call to peek(), which will return the provided operation (may be + * null). + */ + public void expectPeek(WaveletOperation op) { + expectations.add(new Object[] {Method.PEEK, op}); + } + + /** + * Checks that all expectations have been satisfied. + */ + public void checkExpectationsSatisfied() { + Assert.assertTrue("Unsatisfied expectations", expectations.isEmpty()); + } + + @Override + public void setListener(Listener listener) { + // Do nothing. + } + + @Override + public void send(WaveletOperation... operations) { + Object[] expected = expectations.remove(); + Assert.assertEquals(expected[0], Method.SEND); + Assert.assertEquals(expected[1], operations); + } + + @Override + public WaveletOperation receive() { + Object[] expected = expectations.remove(); + Assert.assertEquals(expected[0], Method.RECEIVE); + return (WaveletOperation) expected[1]; + } + + @Override + public WaveletOperation peek() { + Object[] expected = expectations.remove(); + Assert.assertEquals(expected[0], Method.PEEK); + return (WaveletOperation) expected[1]; + } + + @Override + public List<HashedVersion> getReconnectVersions() { + throw new UnsupportedOperationException("Reconnection not supported"); + } + + @Override + public String getDebugString() { + return "[Mock operation channel]"; + } +} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/70f39328/test/org/waveprotocol/wave/concurrencycontrol/testing/MockWaveViewService.java ---------------------------------------------------------------------- diff --git a/test/org/waveprotocol/wave/concurrencycontrol/testing/MockWaveViewService.java b/test/org/waveprotocol/wave/concurrencycontrol/testing/MockWaveViewService.java new file mode 100755 index 0000000..ff1879f --- /dev/null +++ b/test/org/waveprotocol/wave/concurrencycontrol/testing/MockWaveViewService.java @@ -0,0 +1,122 @@ +/** + * 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.concurrencycontrol.testing; + +import junit.framework.Assert; + +import org.waveprotocol.wave.concurrencycontrol.channel.WaveViewService; +import org.waveprotocol.wave.model.id.IdFilter; +import org.waveprotocol.wave.model.id.WaveId; +import org.waveprotocol.wave.model.id.WaveletId; +import org.waveprotocol.wave.model.id.WaveletName; +import org.waveprotocol.wave.model.operation.wave.WaveletDelta; +import org.waveprotocol.wave.model.version.HashedVersion; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * Mock WaveViewService. Captures arguments for easy access in tests. + * + */ +public class MockWaveViewService implements WaveViewService { + public static class OpenArguments { + public final IdFilter waveletFilter; + public final Map<WaveletId, List<HashedVersion>> knownWavelets; + public final OpenCallback callback; + + private OpenArguments(IdFilter waveletFilter, + Map<WaveletId, List<HashedVersion>> knownWavelets, OpenCallback callback) { + this.waveletFilter = waveletFilter; + this.knownWavelets = knownWavelets; + this.callback = callback; + } + } + + public static class SubmitArguments { + public final WaveletName wavelet; + public final WaveletDelta delta; + public final String channelId; + public final SubmitCallback callback; + + private SubmitArguments(WaveletName wavelet, WaveletDelta delta, String channelId, + SubmitCallback callback) { + this.wavelet = wavelet; + this.delta = delta; + this.channelId = channelId; + this.callback = callback; + } + } + + public static class CloseArguments { + public final WaveId waveId; + public final String channelId; + public final CloseCallback callback; + + private CloseArguments(WaveId waveId, String channelId, CloseCallback callback) { + this.waveId = waveId; + this.channelId = channelId; + this.callback = callback; + } + } + + public final List<OpenArguments> opens = new ArrayList<OpenArguments>(); + public final List<SubmitArguments> submits = new ArrayList<SubmitArguments>(); + public final List<CloseArguments> closes = new ArrayList<CloseArguments>(); + + public OpenArguments lastOpen() { + Assert.assertFalse(opens.isEmpty()); + return opens.get(opens.size() - 1); + } + + public SubmitArguments lastSubmit() { + Assert.assertFalse(submits.isEmpty()); + return submits.get(submits.size() - 1); + } + + public CloseArguments lastClose() { + Assert.assertFalse(closes.isEmpty()); + return closes.get(closes.size() - 1); + } + + @Override + public void viewOpen(IdFilter waveletFilter, Map<WaveletId, List<HashedVersion>> knownWavelets, + OpenCallback callback) { + opens.add(new OpenArguments(waveletFilter, knownWavelets, callback)); + } + + @Override + public String viewSubmit(WaveletName wavelet, WaveletDelta delta, String channelId, + SubmitCallback callback) { + submits.add(new SubmitArguments(wavelet, delta, channelId, callback)); + return null; + } + + @Override + public void viewClose(WaveId waveId, String channelId, CloseCallback callback) { + closes.add(new CloseArguments(waveId, channelId, callback)); + } + + @Override + public String debugGetProfilingInfo(String requestId) { + return ""; + } +} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/70f39328/test/org/waveprotocol/wave/model/conversation/testing/BlipTestUtils.java ---------------------------------------------------------------------- diff --git a/test/org/waveprotocol/wave/model/conversation/testing/BlipTestUtils.java b/test/org/waveprotocol/wave/model/conversation/testing/BlipTestUtils.java new file mode 100644 index 0000000..4bdf453 --- /dev/null +++ b/test/org/waveprotocol/wave/model/conversation/testing/BlipTestUtils.java @@ -0,0 +1,94 @@ +/** + * 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.conversation.testing; + +import org.waveprotocol.wave.model.conversation.Blips; +import org.waveprotocol.wave.model.conversation.ConversationBlip; +import org.waveprotocol.wave.model.conversation.TitleHelper; + +import org.waveprotocol.wave.model.document.ReadableWDocument; +import org.waveprotocol.wave.model.document.indexed.IndexedDocument; +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.DocHelper; +import org.waveprotocol.wave.model.document.util.DocProviders; +import org.waveprotocol.wave.model.document.util.LineContainers; +import org.waveprotocol.wave.model.document.util.XmlStringBuilder; + +/** + * Utility functions used by conversation tests. + * + */ +public final class BlipTestUtils { + + // Non-instantiatable class + private BlipTestUtils() { + } + + /** + * Returns the position of the body element in an initial, empty, blip. + */ + public static int getInitialBlipBodyPosition() { + IndexedDocument<Node, Element, Text> d = DocProviders.POJO.build( + TitleHelper.emptyDocumentWithTitle(), + DocumentSchema.NO_SCHEMA_CONSTRAINTS); + return getBodyPosition(d); + } + + + /** + * Returns the position of the body element of the given blip. + */ + public static int getBodyPosition(ConversationBlip blip) { + return getBodyPosition(blip.getContent()); + } + + /** + * Returns the position of the body element of the given document or 0 if the + * document has no body. + */ + public static <N, E extends N> int getBodyPosition(ReadableWDocument<N, E, ?> doc) { + N body = DocHelper.getElementWithTagName(doc, Blips.BODY_TAGNAME); + if (body == null) return 0; + return doc.getLocation(body); + } + + /** + * Wrap the given xml string containing a blip body in an XmlStringBuilder + * and prepend an empty head. + */ + public static XmlStringBuilder prependHead(String body) { + return XmlStringBuilder.createEmpty() + .append(Blips.INITIAL_HEAD) + .append(XmlStringBuilder.createFromXmlString(body)); + } + + /** + * Returns a blip whose contents are the given lines. + */ + public static String debugBlipWrap(String ... lines) { + return XmlStringBuilder.createEmpty() + .append(Blips.INITIAL_HEAD) + .append(XmlStringBuilder.createFromXmlString(LineContainers.debugContainerWrap(lines))) + .toString(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/70f39328/test/org/waveprotocol/wave/model/conversation/testing/FakeConversationView.java ---------------------------------------------------------------------- diff --git a/test/org/waveprotocol/wave/model/conversation/testing/FakeConversationView.java b/test/org/waveprotocol/wave/model/conversation/testing/FakeConversationView.java new file mode 100644 index 0000000..85b2fd9 --- /dev/null +++ b/test/org/waveprotocol/wave/model/conversation/testing/FakeConversationView.java @@ -0,0 +1,159 @@ +/** + * 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.conversation.testing; + +import org.waveprotocol.wave.model.conversation.ObservableConversationView; +import org.waveprotocol.wave.model.conversation.WaveBasedConversationView; +import org.waveprotocol.wave.model.conversation.WaveletBasedConversation; +import org.waveprotocol.wave.model.id.IdGenerator; +import org.waveprotocol.wave.model.id.WaveId; +import org.waveprotocol.wave.model.schema.SchemaProvider; +import org.waveprotocol.wave.model.schema.conversation.ConversationSchemas; +import org.waveprotocol.wave.model.testing.FakeIdGenerator; +import org.waveprotocol.wave.model.testing.FakeWaveView; +import org.waveprotocol.wave.model.wave.ParticipantId; +import org.waveprotocol.wave.model.wave.data.DocumentFactory; +import org.waveprotocol.wave.model.wave.opbased.ObservableWaveView; + +import java.util.Collection; + +/** + * A fake conversation view. The view is fully functioning but not attached to + * any communication channels. + * + * @author [email protected] (Alex North) + */ +public final class FakeConversationView implements ObservableConversationView { + + private final static SchemaProvider DEFAULT_SCHEMAS = new ConversationSchemas(); + + public final static class Builder { + private SchemaProvider schemas; + private IdGenerator idGenerator; + private WaveId waveId; + private ParticipantId viewer; + private DocumentFactory<?> docFactory; + + private Builder() { + } + + public Builder with(DocumentFactory<?> docFactory) { + this.docFactory = docFactory; + return this; + } + + public Builder with(SchemaProvider schemas) { + this.schemas = schemas; + return this; + } + + public Builder with(IdGenerator idGenerator) { + this.idGenerator = idGenerator; + return this; + } + + public Builder with(WaveId wid) { + this.waveId = wid; + return this; + } + + public Builder with(ParticipantId viewer) { + this.viewer = viewer; + return this; + } + + public FakeConversationView build() { + if (schemas == null) { + schemas = DEFAULT_SCHEMAS; + } + if (idGenerator == null) { + idGenerator = FakeIdGenerator.create(); + } + if (waveId == null) { + waveId = idGenerator.newWaveId(); + } + + FakeWaveView waveView = FakeWaveView.builder(schemas) // \u2620 + .with(docFactory) // \u2620 + .with(idGenerator) // \u2620 + .with(waveId) // \u2620 + .with(viewer) // \u2620 + .build(); + + return new FakeConversationView(WaveBasedConversationView.create(waveView, idGenerator)); + } + } + + /** Creates a new conversation view builder. */ + public static Builder builder() { + return new Builder(); + } + + /** The backing conversation view. */ + private final WaveBasedConversationView view; + + private FakeConversationView(WaveBasedConversationView view) { + this.view = view; + } + + @Override + public String getId() { + return view.getId(); + } + + @Override + public WaveletBasedConversation createConversation() { + return view.createConversation(); + } + + @Override + public WaveletBasedConversation createRoot() { + return view.createRoot(); + } + + @Override + public WaveletBasedConversation getConversation(String conversationId) { + return view.getConversation(conversationId); + } + + @Override + public Collection<? extends WaveletBasedConversation> getConversations() { + return view.getConversations(); + } + + @Override + public WaveletBasedConversation getRoot() { + return view.getRoot(); + } + + @Override + public void addListener(Listener listener) { + view.addListener(listener); + } + + @Override + public void removeListener(Listener listener) { + view.removeListener(listener); + } + + public ObservableWaveView getWaveView() { + return view.getWaveView(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/70f39328/test/org/waveprotocol/wave/model/testing/BasicFactories.java ---------------------------------------------------------------------- diff --git a/test/org/waveprotocol/wave/model/testing/BasicFactories.java b/test/org/waveprotocol/wave/model/testing/BasicFactories.java new file mode 100644 index 0000000..f23e93b --- /dev/null +++ b/test/org/waveprotocol/wave/model/testing/BasicFactories.java @@ -0,0 +1,239 @@ +/** + * 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.testing; + +import org.waveprotocol.wave.model.document.Document; +import org.waveprotocol.wave.model.document.ObservableDocument; +import org.waveprotocol.wave.model.document.indexed.IndexedDocument; +import org.waveprotocol.wave.model.document.operation.DocInitialization; +import org.waveprotocol.wave.model.document.operation.DocOp; +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.DocProviders; +import org.waveprotocol.wave.model.document.util.DocumentImpl; +import org.waveprotocol.wave.model.document.util.DocumentProvider; +import org.waveprotocol.wave.model.operation.SilentOperationSink; +import org.waveprotocol.wave.model.schema.SchemaCollection; +import org.waveprotocol.wave.model.schema.SchemaProvider; +import org.waveprotocol.wave.model.util.Preconditions; +import org.waveprotocol.wave.model.wave.data.DocumentFactory; +import org.waveprotocol.wave.model.wave.data.MuteDocumentFactory; +import org.waveprotocol.wave.model.wave.data.impl.ObservablePluggableMutableDocument; +import org.waveprotocol.wave.model.wave.data.impl.PluggableMutableDocument; +import org.waveprotocol.wave.model.wave.data.impl.WaveletDataImpl; + +import java.util.Map; + +/** + * Static factory for creating various document factories and builders whose + * document schemas come from the provider set using + * {@link #setSchemaProvider(SchemaProvider)}. If no provider is set the empty + * provider is used. This should only be used for tests of the core model. + * + */ +public class BasicFactories { + + /** + * Provider of {@link Document}s based on the {@link DocProviders#POJO} DOM + * implementation. + */ + private static final DocumentProvider<Document> DOC_PROVIDER = new DocumentProvider<Document>() { + @Override + public Document create(String tagName, Map<String, String> attributes) { + IndexedDocument<Node, Element, Text> doc = DocProviders.POJO.create(tagName, attributes); + return new DocumentImpl(DocProviders.createTrivialSequencer(doc), doc); + } + + @Override + public Document parse(String text) { + IndexedDocument<Node, Element, Text> doc = DocProviders.POJO.parse(text); + return new DocumentImpl(DocProviders.createTrivialSequencer(doc), doc); + } + }; + + /** + * Provider of {@link ObservableDocument}s based on the + * {@link DocProviders#POJO} DOM implementation and a trivial sequence. + */ + private static final DocumentProvider<ObservablePluggableMutableDocument> OBS_DOC_PROVIDER = + new DocumentProvider<ObservablePluggableMutableDocument>() { + @Override + public ObservablePluggableMutableDocument create( + String tagName, Map<String, String> attributes) { + // FIXME(ohler): this is inefficient. + return build(DocProviders.POJO.create(tagName, attributes).asOperation()); + } + + @Override + public ObservablePluggableMutableDocument parse(String text) { + // FIXME(ohler): this is inefficient. + return build(DocProviders.POJO.parse(text).asOperation()); + } + + private ObservablePluggableMutableDocument build(DocInitialization init) { + ObservablePluggableMutableDocument doc = + new ObservablePluggableMutableDocument(DocumentSchema.NO_SCHEMA_CONSTRAINTS, init); + doc.init(SilentOperationSink.VOID); + return doc; + } + }; + + private static SchemaProvider schemas = SchemaCollection.empty(); + + /** + * Sets the schema provider that will provide schemas for the factories + * returned from the methods of this class. + */ + public static void setSchemaProvider(SchemaProvider value) { + schemas = value; + } + + /** + * Returns the current schema provider. + */ + protected static SchemaProvider getSchemas() { + return schemas; + } + + /** + * Returns a new fake wave view builder whose document schemas comes from the + * current provider. + */ + public static FakeWaveView.Builder fakeWaveViewBuilder() { + return FakeWaveView.builder(getSchemas()); + } + + /** + * Returns a new op-based wavelet factory builder whose document schemas comes + * from the current provider. + */ + public static OpBasedWaveletFactory.Builder opBasedWaveletFactoryBuilder() { + return OpBasedWaveletFactory.builder(getSchemas()); + } + + /** + * Returns a new wavelet data impl factory whose document schemas comes from + * the current provider. + */ + public static WaveletDataImpl.Factory waveletDataImplFactory() { + return WaveletDataImpl.Factory.create(observablePluggableMutableDocumentFactory()); + } + + /** + * Returns a mute document factory whose document schemas comes from the + * current provider. + */ + public static MuteDocumentFactory muteDocumentFactory() { + return new MuteDocumentFactory(getSchemas()); + } + + /** + * Returns a fake document factory whose document schemas comes from the + * current provider. + */ + public static FakeDocument.Factory fakeDocumentFactory() { + return FakeDocument.Factory.create(getSchemas()); + } + + /** + * Returns a plugable mutable document factory whose document schemas comes + * from the current provider. + */ + public static DocumentFactory<? extends PluggableMutableDocument> + pluggableMutableDocumentFactory() { + return PluggableMutableDocument.createFactory(getSchemas()); + } + + /** + * Returns an observable pluggable mutable document factory whose document + * schemas comes from the current provider. + */ + public static DocumentFactory<? extends ObservablePluggableMutableDocument> + observablePluggableMutableDocumentFactory() { + return ObservablePluggableMutableDocument.createFactory(getSchemas()); + } + + /** + * Returns a provider of {@link Document}s. + * + * Provided documents have no schema constraints: consider using + * {@link MuteDocumentFactory} instead. + * + * TODO(anorth): Remove this method in favor of one specifying a schema. + */ + public static DocumentProvider<Document> documentProvider() { + return DOC_PROVIDER; + } + + /** + * Returns a provider of observable mutable documents. + * + * Provided documents have no schema constraints: consider using + * {@link MuteDocumentFactory} instead. + * + * TODO(anorth): Change generic type to ObservableDocument after fixing + * callers. + * + * TODO(anorth): Remove this method in favor of one specifying a schema. + */ + public static DocumentProvider<ObservablePluggableMutableDocument> observableDocumentProvider() { + return OBS_DOC_PROVIDER; + } + + /** + * Creates an observable mutable document with some schema, content, and sink. + */ + public static ObservableDocument createDocument(DocumentSchema schema, + String initialContent, SilentOperationSink<? super DocOp> sink) { + Preconditions.checkNotNull(sink, "Sink can't be null"); + DocInitialization init = DocProviders.POJO.parse(initialContent).asOperation(); + ObservablePluggableMutableDocument doc = new ObservablePluggableMutableDocument(schema, init); + doc.init(sink); + return doc; + } + + /** + * Creates an observable mutable document with some schema and a sink. + */ + public static ObservableDocument createDocument( + DocumentSchema schema, SilentOperationSink<? super DocOp> sink) { + return createDocument(schema, "", sink); + } + + /** + * Creates an observable mutable document with some schema. + */ + public static ObservableDocument createDocument(DocumentSchema schema) { + return createDocument(schema, "", SilentOperationSink.VOID); + } + + /** + * Creates an observable mutable document with some schema and initial content + */ + public static ObservableDocument createDocument( + DocumentSchema schema, String initialContent) { + return createDocument(schema, initialContent, SilentOperationSink.VOID); + } + + protected BasicFactories() { + } +} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/70f39328/test/org/waveprotocol/wave/model/testing/DeltaTestUtil.java ---------------------------------------------------------------------- diff --git a/test/org/waveprotocol/wave/model/testing/DeltaTestUtil.java b/test/org/waveprotocol/wave/model/testing/DeltaTestUtil.java new file mode 100755 index 0000000..2bd7021 --- /dev/null +++ b/test/org/waveprotocol/wave/model/testing/DeltaTestUtil.java @@ -0,0 +1,199 @@ +/** + * 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.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 [email protected] (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)); + } +} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/70f39328/test/org/waveprotocol/wave/model/testing/DocOpCreator.java ---------------------------------------------------------------------- diff --git a/test/org/waveprotocol/wave/model/testing/DocOpCreator.java b/test/org/waveprotocol/wave/model/testing/DocOpCreator.java new file mode 100644 index 0000000..31f589b --- /dev/null +++ b/test/org/waveprotocol/wave/model/testing/DocOpCreator.java @@ -0,0 +1,266 @@ +/** + * 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.testing; + +import org.waveprotocol.wave.model.document.operation.Attributes; +import org.waveprotocol.wave.model.document.operation.AttributesUpdate; +import org.waveprotocol.wave.model.document.operation.DocOp; +import org.waveprotocol.wave.model.document.operation.EvaluatingDocOpCursor; +import org.waveprotocol.wave.model.document.operation.impl.AnnotationBoundaryMapImpl; +import org.waveprotocol.wave.model.document.operation.impl.AttributesUpdateImpl; +import org.waveprotocol.wave.model.document.operation.impl.DocOpBuffer; +import org.waveprotocol.wave.model.util.Preconditions; + +/** + * A convenience class for creating document operations. + * + */ +public class DocOpCreator { + + /** + * A builder for BufferedDocOps which is used by the static convenience + * methods of DocOpCreator for creating operations. This builder allows + * calling "retain" with an argument of 0 and "characters" and + * "deleteCharacters" with an empty string argument, in order to make the + * building process easier in some circumstances. + */ + private static class SimplifyingDocOpBuilder { + + private final EvaluatingDocOpCursor<DocOp> buffer = new DocOpBuffer(); + + public final DocOp build() { + return buffer.finish(); + } + + public final SimplifyingDocOpBuilder retain(int itemCount) { + Preconditions.checkArgument(itemCount >= 0, "Negative item count"); + if (itemCount > 0) { + buffer.retain(itemCount); + } + return this; + } + + public final SimplifyingDocOpBuilder characters(String characters) { + if (characters.length() > 0) { + buffer.characters(characters); + } + return this; + } + + public final SimplifyingDocOpBuilder elementStart(String type, Attributes attrs) { + buffer.elementStart(type, attrs); + return this; + } + + public final SimplifyingDocOpBuilder elementEnd() { + buffer.elementEnd(); + return this; + } + + public final SimplifyingDocOpBuilder deleteCharacters(String characters) { + if (characters.length() > 0) { + buffer.deleteCharacters(characters); + } + return this; + } + + public final SimplifyingDocOpBuilder deleteElementStart(String type, Attributes attrs) { + buffer.deleteElementStart(type, attrs); + return this; + } + + public final SimplifyingDocOpBuilder deleteElementEnd() { + buffer.deleteElementEnd(); + return this; + } + + public final SimplifyingDocOpBuilder replaceAttributes(Attributes oldAttrs, + Attributes newAttrs) { + buffer.replaceAttributes(oldAttrs, newAttrs); + return this; + } + + public final SimplifyingDocOpBuilder updateAttributes(AttributesUpdate update) { + buffer.updateAttributes(update); + return this; + } + + public final SimplifyingDocOpBuilder setAnnotation(int itemCount, String key, String oldValue, + String newValue) { + Preconditions.checkArgument(itemCount >= 0, "Negative item count"); + if (itemCount > 0) { + buffer.annotationBoundary(AnnotationBoundaryMapImpl.builder() + .updateValues(key, oldValue, newValue) + .build()); + buffer.retain(itemCount); + buffer.annotationBoundary(AnnotationBoundaryMapImpl.builder() + .initializationEnd(key) + .build()); + } + return this; + } + + } + + /** + * Creates a document operation that inserts the given characters at the given + * location. + * + * @param size The initial size of the document. + * @param location The location at which to insert characters. + * @param characters The characters to insert. + * @return The document operation. + */ + public static DocOp insertCharacters(int size, int location, String characters) { + return new SimplifyingDocOpBuilder() + .retain(location) + .characters(characters) + .retain(size - location) + .build(); + } + + /** + * Creates a document operation that inserts an element at the given location. + * + * @param size The initial size of the document. + * @param location The location at which to insert the element. + * @param type The type of the element. + * @param attributes The attributes of the element. + * @return The document operation. + */ + public static DocOp insertElement(int size, int location, String type, + Attributes attributes) { + return new SimplifyingDocOpBuilder() + .retain(location) + .elementStart(type, attributes) + .elementEnd() + .retain(size - location) + .build(); + } + + /** + * Creates a document operation that deletes the characters denoted by the + * given range. + * + * @param size The initial size of the document. + * @param location The location the characters to delete. + * @param characters The characters to delete. + * @return The document operation. + */ + public static DocOp deleteCharacters(int size, int location, String characters) { + return new SimplifyingDocOpBuilder() + .retain(location) + .deleteCharacters(characters) + .retain(size - location - characters.length()) + .build(); + } + + /** + * Creates a document operation that deletes an empty element at a given + * location. + * + * @param size The initial size of the document. + * @param location The location of the element to delete. + * @param type The type of the element. + * @param attributes The attributes of the element. + * @return The document operation. + */ + public static DocOp deleteElement(int size, int location, String type, + Attributes attributes) { + return new SimplifyingDocOpBuilder() + .retain(location) + .deleteElementStart(type, attributes) + .deleteElementEnd() + .retain(size - location - 2) + .build(); + } + + /** + * Creates a document operation that replace all the attributes of an element. + * + * @param size The initial size of the document. + * @param location The location of the element whose attributes are to be set. + * @param oldAttr The old attributes of the element. + * @param newAttr The new attributes that the element should have. + * @return The document operation. + */ + public static DocOp replaceAttributes(int size, int location, Attributes oldAttr, + Attributes newAttr) { + return new SimplifyingDocOpBuilder() + .retain(location) + .replaceAttributes(oldAttr, newAttr) + .retain(size - location - 1) + .build(); + } + + /** + * Creates a document operation that sets an attribute of an element. + * + * @param size The initial size of the document. + * @param location The location of the element whose attribute is to be set. + * @param name The name of the attribute to set. + * @param oldValue The old value of the attribute. + * @param newValue The value to which to set the attribute. + * @return The document operation. + */ + public static DocOp setAttribute(int size, int location, String name, String oldValue, + String newValue) { + return new SimplifyingDocOpBuilder() + .retain(location) + .updateAttributes(new AttributesUpdateImpl(name, oldValue, newValue)) + .retain(size - location - 1) + .build(); + } + + /** + * Creates a document operation that sets an annotation over a range. + * + * @param size The initial size of the document. + * @param start The location of the start of the range on which the annotation + * is to be set. + * @param end The location of the end of the range on which the annotation is + * to be set. + * @param key The annotation key. + * @param oldValue The old annotation value. + * @param newValue The new annotation value. + * @return The document operation. + */ + public static DocOp setAnnotation(int size, int start, int end, String key, + String oldValue, String newValue) { + return new SimplifyingDocOpBuilder() + .retain(start) + .setAnnotation(end - start, key, oldValue, newValue) + .retain(size - end) + .build(); + } + + /** + * Creates a document operation that acts as the identity on a document. + * + * @param size The size of the document. + * @return The document operation. + */ + public static DocOp identity(int size) { + return new SimplifyingDocOpBuilder() + .retain(size) + .build(); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/70f39328/test/org/waveprotocol/wave/model/testing/ExtraAsserts.java ---------------------------------------------------------------------- diff --git a/test/org/waveprotocol/wave/model/testing/ExtraAsserts.java b/test/org/waveprotocol/wave/model/testing/ExtraAsserts.java new file mode 100644 index 0000000..989240b --- /dev/null +++ b/test/org/waveprotocol/wave/model/testing/ExtraAsserts.java @@ -0,0 +1,92 @@ +/** + * 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.testing; + +import org.waveprotocol.wave.model.wave.data.BlipData; + +import junit.framework.Assert; + +import org.waveprotocol.wave.model.document.MutableDocument; +import org.waveprotocol.wave.model.document.ReadableWDocument; +import org.waveprotocol.wave.model.document.operation.impl.DocOpUtil; +import org.waveprotocol.wave.model.document.util.DocCompare; +import org.waveprotocol.wave.model.document.util.XmlStringBuilder; + +/** + * Extra assertions that are useful for tests involving the model. + * + */ +public final class ExtraAsserts { + + /** + * Asserts that the structure of the document and the builder are the same. + */ + public static <N, E extends N, T extends N> void assertStructureEquivalent( + XmlStringBuilder expected, MutableDocument<N, E, T> doc) { + String expectedStr = expected.getXmlString(); + if (!DocCompare.equivalent(DocCompare.STRUCTURE, expectedStr, doc)) { + String docStr = doc.toXmlString(); + String message = "Expected [" + expectedStr + "], found [" + docStr + "]"; + Assert.fail(message); + } + } + + /** + * Asserts that the structure of the two documents are the same. + */ + public static <N1, N2> void assertStructureEquivalent(ReadableWDocument<N1, ?, ?> doc1, + ReadableWDocument<N2, ?, ?> doc2) { + if (!DocCompare.equivalent(DocCompare.STRUCTURE, doc1, doc2)) { + String doc1Str = doc1.toXmlString(); + String doc2Str = doc2.toXmlString(); + String message = "Expected [" + doc1Str + "] found [" + doc2Str + "]"; + Assert.fail(message); + } + } + + /** + * Asserts that the content, both structure and annotations, of the document + * and the builder are the same. + */ + public static <N, E extends N, T extends N> void assertEqual( + XmlStringBuilder expected, MutableDocument<N, E, T> doc) { + String expectedStr = expected.getXmlString(); + if (!DocCompare.equivalent(DocCompare.ALL, expectedStr, doc)) { + String docStr = doc.toXmlString(); + String message = "Expected [" + expectedStr + "], found [" + docStr + "]"; + Assert.fail(message); + } + } + + // Static utility class + private ExtraAsserts() { } + + /** + * Checks the content of a document and asserts it matches the given expected + * content. + * + * @param expectedContent The expected content. + * @param root The content to check. + */ + public static void checkContent(String expectedContent, BlipData root) { + Assert.assertEquals(expectedContent, DocOpUtil.toXmlString(root.getContent().asOperation())); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/70f39328/test/org/waveprotocol/wave/model/testing/Factory.java ---------------------------------------------------------------------- diff --git a/test/org/waveprotocol/wave/model/testing/Factory.java b/test/org/waveprotocol/wave/model/testing/Factory.java new file mode 100644 index 0000000..7ae8f7a --- /dev/null +++ b/test/org/waveprotocol/wave/model/testing/Factory.java @@ -0,0 +1,34 @@ +/** + * 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.testing; + +/** + * Generic factory interface. The intended use within this test package is + * to allow black-box tests, which only test an interface, to be decoupled from + * the construction of the particular instance of that interface to test. + * + * @param <T> type of created instances + */ +public interface Factory<T> { + /** + * Creates an instance. + */ + T create(); +} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/70f39328/test/org/waveprotocol/wave/model/testing/FakeDocument.java ---------------------------------------------------------------------- diff --git a/test/org/waveprotocol/wave/model/testing/FakeDocument.java b/test/org/waveprotocol/wave/model/testing/FakeDocument.java new file mode 100644 index 0000000..33de8c1 --- /dev/null +++ b/test/org/waveprotocol/wave/model/testing/FakeDocument.java @@ -0,0 +1,81 @@ +/** + * 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.testing; + +import org.waveprotocol.wave.model.document.operation.DocInitialization; +import org.waveprotocol.wave.model.document.operation.DocOp; +import org.waveprotocol.wave.model.document.operation.automaton.DocumentSchema; +import org.waveprotocol.wave.model.id.WaveletId; +import org.waveprotocol.wave.model.operation.OperationException; +import org.waveprotocol.wave.model.schema.SchemaProvider; +import org.waveprotocol.wave.model.wave.data.DocumentFactory; +import org.waveprotocol.wave.model.wave.data.impl.ObservablePluggableMutableDocument; + +/** + * A document implementation and factory for use in tests. + * + */ +public class FakeDocument extends ObservablePluggableMutableDocument { + + public static class Factory implements DocumentFactory<FakeDocument> { + + private final SchemaProvider schemas; + + public static Factory create(SchemaProvider schemas) { + return new Factory(schemas); + } + + private Factory(SchemaProvider schemas) { + this.schemas = schemas; + } + + private DocumentSchema getSchemaForId(WaveletId waveletId, String documentId) { + DocumentSchema result = schemas.getSchemaForId(waveletId, documentId); + return (result != null) ? result : DocumentSchema.NO_SCHEMA_CONSTRAINTS; + } + + @Override + public FakeDocument create(final WaveletId waveletId, final String blipId, + DocInitialization content) { + return new FakeDocument(content, getSchemaForId(waveletId, blipId)); + } + } + + private DocOp consumed; + + public FakeDocument(DocInitialization initial, DocumentSchema schema) { + super(schema, initial); + } + + @Override + public void consume(DocOp op) throws OperationException { + super.consume(op); + this.consumed = op; + } + + public DocOp getConsumed() { + return consumed; + } + + @Override + public String toString() { + return toXmlString(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/70f39328/test/org/waveprotocol/wave/model/testing/FakeHashedVersionFactory.java ---------------------------------------------------------------------- diff --git a/test/org/waveprotocol/wave/model/testing/FakeHashedVersionFactory.java b/test/org/waveprotocol/wave/model/testing/FakeHashedVersionFactory.java new file mode 100644 index 0000000..e9d25b8 --- /dev/null +++ b/test/org/waveprotocol/wave/model/testing/FakeHashedVersionFactory.java @@ -0,0 +1,45 @@ +/** + * 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.testing; + +import org.waveprotocol.wave.model.id.WaveletName; +import org.waveprotocol.wave.model.version.HashedVersion; +import org.waveprotocol.wave.model.version.HashedVersionFactory; + +/** + * A hashed version factory which generates unsigned versions. + * + * @author [email protected] (Alex North) + */ +public final class FakeHashedVersionFactory implements HashedVersionFactory { + + public static final HashedVersionFactory INSTANCE = new FakeHashedVersionFactory(); + + @Override + public HashedVersion createVersionZero(WaveletName waveletName) { + return HashedVersion.unsigned(0); + } + + @Override + public HashedVersion create(byte[] appliedDeltaBytes, HashedVersion versionAppliedAt, + int opsApplied) { + return HashedVersion.unsigned(versionAppliedAt.getVersion() + opsApplied); + } +} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/70f39328/test/org/waveprotocol/wave/model/testing/FakeIdGenerator.java ---------------------------------------------------------------------- diff --git a/test/org/waveprotocol/wave/model/testing/FakeIdGenerator.java b/test/org/waveprotocol/wave/model/testing/FakeIdGenerator.java new file mode 100644 index 0000000..f46802c --- /dev/null +++ b/test/org/waveprotocol/wave/model/testing/FakeIdGenerator.java @@ -0,0 +1,44 @@ +/** + * 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.testing; + +import org.waveprotocol.wave.model.id.IdGenerator; +import org.waveprotocol.wave.model.id.IdGeneratorImpl; +import org.waveprotocol.wave.model.id.IdGeneratorImpl.Seed; + + +/** + * Id generator suitable for use in testing. + * + */ +public final class FakeIdGenerator { + + // Prevent instantiation + private FakeIdGenerator() {} + + public static IdGenerator create() { + return new IdGeneratorImpl("example.com", new Seed() { + @Override + public String get() { + return "seed"; + } + }); + } +} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/70f39328/test/org/waveprotocol/wave/model/testing/FakeSilentOperationSink.java ---------------------------------------------------------------------- diff --git a/test/org/waveprotocol/wave/model/testing/FakeSilentOperationSink.java b/test/org/waveprotocol/wave/model/testing/FakeSilentOperationSink.java new file mode 100644 index 0000000..43bbd34 --- /dev/null +++ b/test/org/waveprotocol/wave/model/testing/FakeSilentOperationSink.java @@ -0,0 +1,69 @@ +/** + * 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.testing; + +import org.waveprotocol.wave.model.operation.Operation; +import org.waveprotocol.wave.model.operation.SilentOperationSink; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +/** + * A place where you can get a concrete OperationSink.Silent for testing. + * + * @author [email protected] (David Wang) + */ +public class FakeSilentOperationSink<T extends Operation<?>> implements SilentOperationSink<T> { + private LinkedList<T> ops = new LinkedList<T>(); + + /** + * For unit testing + * @return the most recently consumed op + */ + public T getConsumedOp() { + int size = ops.size(); + return (size == 0) ? null : (ops.get(size - 1)); + } + + /** + * {@inheritDoc} + */ + public void consume(T op) { + ops.addLast(op); + } + + /** + * Clears the list of saved operations. + */ + public void clear() { + ops.clear(); + } + + /** + * Gets the list of operations consumed by this sink since it was last + * cleared. + * + * @return the ops, from first consumed through most recently consumed. + */ + public List<T> getOps() { + return Collections.unmodifiableList(ops); + } +} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/70f39328/test/org/waveprotocol/wave/model/testing/FakeWaveView.java ---------------------------------------------------------------------- diff --git a/test/org/waveprotocol/wave/model/testing/FakeWaveView.java b/test/org/waveprotocol/wave/model/testing/FakeWaveView.java new file mode 100644 index 0000000..5f74e11 --- /dev/null +++ b/test/org/waveprotocol/wave/model/testing/FakeWaveView.java @@ -0,0 +1,229 @@ +/** + * 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.testing; + +import org.waveprotocol.wave.model.id.IdGenerator; +import org.waveprotocol.wave.model.id.WaveId; +import org.waveprotocol.wave.model.id.WaveletId; +import org.waveprotocol.wave.model.operation.SilentOperationSink; +import org.waveprotocol.wave.model.operation.wave.WaveletOperation; +import org.waveprotocol.wave.model.operation.wave.WaveletOperationContext; +import org.waveprotocol.wave.model.schema.SchemaProvider; +import org.waveprotocol.wave.model.wave.ObservableWavelet; +import org.waveprotocol.wave.model.wave.ParticipantId; +import org.waveprotocol.wave.model.wave.WaveViewListener; +import org.waveprotocol.wave.model.wave.data.DocumentFactory; +import org.waveprotocol.wave.model.wave.data.impl.WaveletDataImpl; +import org.waveprotocol.wave.model.wave.opbased.ObservableWaveView; +import org.waveprotocol.wave.model.wave.opbased.OpBasedWavelet; +import org.waveprotocol.wave.model.wave.opbased.WaveViewImpl; + +/** + * Dummy implementation of a wave view. + * + */ +public final class FakeWaveView implements ObservableWaveView, Factory<OpBasedWavelet> { + + public final static class Builder { + private final SchemaProvider schemas; + private IdGenerator idGenerator; + private WaveId waveId; + private ParticipantId viewer; + private SilentOperationSink<? super WaveletOperation> sink; + private WaveViewImpl.WaveletConfigurator configurator; + private DocumentFactory<?> docFactory; + + private Builder(SchemaProvider schemas) { + this.schemas = schemas; + } + + public Builder with(DocumentFactory<?> docFactory) { + this.docFactory = docFactory; + return this; + } + + public Builder with(IdGenerator idGenerator) { + this.idGenerator = idGenerator; + return this; + } + + public Builder with(WaveId wid) { + this.waveId = wid; + return this; + } + + public Builder with(ParticipantId viewer) { + this.viewer = viewer; + return this; + } + + public Builder with(SilentOperationSink<? super WaveletOperation> sink) { + this.sink = sink; + return this; + } + + public Builder with(WaveViewImpl.WaveletConfigurator configurator) { + this.configurator = configurator; + return this; + } + + public FakeWaveView build() { + if (idGenerator == null) { + idGenerator = FakeIdGenerator.create(); + } + if (waveId == null) { + waveId = idGenerator.newWaveId(); + } + if (viewer == null) { + viewer = FAKE_PARTICIPANT; + } + if (sink == null) { + sink = SilentOperationSink.VOID; + } + if (configurator == null) { + configurator = WaveViewImpl.WaveletConfigurator.ADD_CREATOR; + } + if (docFactory == null) { + // Document factory that accepts output-sink registrations. + docFactory = FakeDocument.Factory.create(schemas); + } + + // Wavelet factory that does all the work. + OpBasedWaveletFactory waveletFactory = OpBasedWaveletFactory // \u2620 + .builder(schemas) // \u2620 + .with(WaveletDataImpl.Factory.create(docFactory)) // \u2620 + .with(sink) // \u2620 + .with(viewer) // \u2620 + .build(); + + // And the view implementation using that factory. + WaveViewImpl<OpBasedWavelet> view = + WaveViewImpl.create(waveletFactory, waveId, idGenerator, viewer, configurator); + + return new FakeWaveView(waveletFactory, view); + } + } + + private static final ParticipantId FAKE_PARTICIPANT = new ParticipantId("[email protected]"); + + private final OpBasedWaveletFactory factory; + private final WaveViewImpl<? extends OpBasedWavelet> view; + + /** + * Creates a wave view. + * + * @param factory factory exposing testing hacks + * @param view real view implementation + */ + private FakeWaveView(OpBasedWaveletFactory factory, WaveViewImpl<? extends OpBasedWavelet> view) { + this.factory = factory; + this.view = view; + } + + /** + * @return a builder for a fake wave view. + */ + public static Builder builder(SchemaProvider schemas) { + return new Builder(schemas); + } + + // + // Expose as basic wavelet factory for wavelet-specific tests. + // + + @Override + public OpBasedWavelet create() { + return createWavelet(); + } + + // + // Testing hacks. + // + + public MockParticipationHelper getLastAuthoriser() { + return factory.getLastAuthoriser(); + } + + public WaveletOperationContext.Factory getLastContextFactory() { + return factory.getLastContextFactory(); + } + + public OpBasedWavelet createWavelet(WaveletId id) { + return view.createWavelet(id); + } + + public void removeWavelet(ObservableWavelet wavelet) { + view.removeWavelet(wavelet); + } + + // + // Delegate view implementation to view. + // + + @Override + public OpBasedWavelet createRoot() { + return view.createRoot(); + } + + @Override + public OpBasedWavelet createUserData() { + return view.createUserData(); + } + + @Override + public OpBasedWavelet createWavelet() { + return view.createWavelet(); + } + + @Override + public OpBasedWavelet getRoot() { + return view.getRoot(); + } + + @Override + public OpBasedWavelet getUserData() { + return view.getUserData(); + } + + @Override + public OpBasedWavelet getWavelet(WaveletId waveletId) { + return view.getWavelet(waveletId); + } + + @Override + public Iterable<? extends OpBasedWavelet> getWavelets() { + return view.getWavelets(); + } + + @Override + public WaveId getWaveId() { + return view.getWaveId(); + } + + @Override + public void addListener(WaveViewListener listener) { + view.addListener(listener); + } + + @Override + public void removeListener(WaveViewListener listener) { + view.removeListener(listener); + } +}
