private static void assertThreadsEquivalent(ConversationThread expected, ConversationThread actual) { assertEquals("Mismatched id in constructed conversation thread", expected.getId(), actual.getId()); assertEquals("Mismatched first blip in constructed conversation thread", expected.getFirstBlip() == null, actual.getFirstBlip() == null); Iterator<? extends ConversationBlip> expectedBlips = expected.getBlips().iterator(); Iterator<? extends ConversationBlip> actualBlips = actual.getBlips().iterator(); while (expectedBlips.hasNext()) { assertTrue("Missing blip in reconstructed conversation", actualBlips.hasNext()); ConversationBlip expectedBlip = expectedBlips.next(); ConversationBlip actualBlip = actualBlips.next(); assertBlipsEquivalent(expectedBlip, actualBlip); } assertFalse("Extra blip in reconstructed conversation", actualBlips.hasNext()); }
/** * Tests that setting a null anchor updates the manifest and makes the wavelet * un-anchored. */ public void testClearAnchorClearsManifest() { WaveletBasedConversation conversation2 = makeConversation(); populate(conversation2); Anchor anchor = conversation2.createAnchor(getFirstBlip(conversation2)); target.setAnchor(anchor); target.setAnchor(null); assertNull(getManifestAttribute(manifestDoc, "anchorWavelet")); assertNull(getManifestAttribute(manifestDoc, "anchorBlip")); }
/** * Tests that a wavelet with a manifest but no anchor attributes is not * anchored. */ public void testMissingAnchorAttributesMeansNoAnchor() { setManifestAttribute(manifestDoc, "sort", "a-value"); assertFalse(target.hasAnchor()); }
/** * Tests that setting an anchor updates the conversation manifest correctly. */ public void testSetAnchorUpdatesManifest() { // Anchor target(wavelet1) in alternate (wavelet2). WaveletBasedConversation conversation2 = makeConversation(); populate(conversation2); ConversationBlip firstBlip = getFirstBlip(conversation2); Anchor anchor = conversation2.createAnchor(firstBlip); target.setAnchor(anchor); assertEquals(WaveletBasedConversation.idFor(conversation2.getWavelet().getId()), getManifestAttribute(manifestDoc, "anchorWavelet")); assertEquals(firstBlip.getId(), getManifestAttribute(manifestDoc, "anchorBlip")); }
public void testConcurrentDeletionOfFinalThreadsLeavesEmptyBlip() { WaveletBasedConversationBlip first = target.getRootThread().appendBlip(); WaveletBasedConversationThread t1 = first.addReplyThread(); WaveletBasedConversationBlip t1b = t1.appendBlip(); WaveletBasedConversationThread t2 = first.addReplyThread(); WaveletBasedConversationBlip t2b = t2.appendBlip(); // Locally delete t1, remotely delete t2. t1b.delete(); first.addListener(blipListener); t2.addListener(threadListener); target.addListener(convListener); remoteRemoveBlip(t2b); remoteRemoveThread(t2); // Expect thread t2 deletion events and it to be invalid. verify(threadListener).onDeleted(); verify(convListener).onBlipDeleted(t2b); verify(convListener).onThreadDeleted(t2); assertBlipInvalid(t2b); assertThreadInvalid(t2); assertBlipValid(first); assertNotNull(target.getRootThread().getFirstBlip()); // The manifest now has an empty blip. assertEquals(0, first.getManifestBlip().numReplies()); // Still there after next write. WaveletBasedConversationBlip second = target.getRootThread().appendBlip(); assertBlipValid(first); verify(convListener).onBlipAdded(second); verifyNoMoreInteractions(blipListener, threadListener, convListener); }
public void testAppendBlipsInRootThreadUpdatesManifest() { WaveletBasedConversationBlip first = target.getRootThread().appendBlip(); assertManifestXml("<blip id=\"" + first.getId() + "\"></blip>"); WaveletBasedConversationBlip second = target.getRootThread().appendBlip(); assertManifestXml("<blip id=\"" + first.getId() + "\"></blip>" + "<blip id=\"" + second.getId() + "\"></blip>"); assertMirrorConversationEquivalent(); }
/** * Test that a conversation can be created on a manifest that contains blips * that are not backed by the wavelet. */ public void testBlipMissingFromWavelet() { WaveletBasedConversation empty = target; WaveletBasedConversation nonEmpty = makeConversation(); nonEmpty.getRootThread().appendBlip(); WaveletBasedConversation conversation = WaveletBasedConversation.create(conversationView, empty.getWavelet(), nonEmpty.getManifest(), idGenerator); assertNull(conversation.getRootThread().getFirstBlip()); assertEquals(Collections.emptyList(), getBlipList(conversation.getRootThread())); }
public void testAppendInlineReplyUpdatesManifest() { WaveletBasedConversationBlip blip = target.getRootThread().appendBlip(); WaveletBasedConversationThread reply = blip.addReplyThread(locateAfterLineElement( blip.getContent())); WaveletBasedConversationBlip replyBlip = reply.appendBlip(); assertManifestXml("<blip id=\"" + blip.getId() + "\">" + "<thread id=\"" + reply.getId() + "\" inline=\"true\">" + "<blip id=\"" + replyBlip.getId() + "\"></blip>" + "</thread>" + "</blip>"); assertEquals(Blips.INITIAL_HEAD + "<body><line></line><reply id=\"" + reply.getId() + "\"></reply></body>", XmlStringBuilder.innerXml(blip.getContent()).toString()); assertMirrorConversationEquivalent(); }
private static void assertBlipsEquivalent(ConversationBlip expected, ConversationBlip actual) { assertEquals("Mismatched id in constructed conversation blip", expected.getId(), actual.getId()); assertEquals("Mismatched author in constructed conversation blip", expected.getAuthorId(), actual.getAuthorId()); assertEquals("Mismatched timestamp in constructed conversation blip", expected.getLastModifiedTime(), actual.getLastModifiedTime()); assertEquals("Mismatched contributors in constructed conversation blip", expected.getContributorIds(), actual.getContributorIds()); Iterator<? extends ConversationThread> expectedThreads = expected.getReplyThreads().iterator(); Iterator<? extends ConversationThread> actualThreads = actual.getReplyThreads().iterator(); while (expectedThreads.hasNext()) { assertTrue("Missing thread in reconstructed conversation", actualThreads.hasNext()); ConversationThread expectedThread = expectedThreads.next(); ConversationThread actualThread = actualThreads.next(); assertThreadsEquivalent(expectedThread, actualThread); } assertFalse("Extra thread in reconstructed conversation", actualThreads.hasNext()); } }
public void testConcrrentDeletionOfFinalBlipsLeavesEmptyThread() { WaveletBasedConversationBlip first = target.getRootThread().appendBlip(); WaveletBasedConversationThread replyThread = first.addReplyThread(); WaveletBasedConversationBlip b1 = replyThread.appendBlip(); WaveletBasedConversationBlip b2 = replyThread.appendBlip(); // Locally delete b1, remotely delete b2. b1.delete(); replyThread.addListener(threadListener); b2.addListener(blipListener); target.addListener(convListener); remoteRemoveBlip(b2); // Expect blip deletion events and it to be invalid. verify(blipListener).onDeleted(); verify(convListener).onBlipDeleted(b2); assertBlipInvalid(b2); assertThreadValid(replyThread); assertEquals(Arrays.asList(replyThread), CollectionUtils.newArrayList(first.getReplyThreads())); // The manifest now has a thread with no blips. assertEquals(1, first.getManifestBlip().numReplies()); assertEquals(0, first.getManifestBlip().getReply(0).numBlips()); // Still there after the next mutation. ObservableConversationBlip second = target.getRootThread().appendBlip(); assertThreadValid(replyThread); assertEquals(Arrays.asList(replyThread), CollectionUtils.newArrayList(first.getReplyThreads())); verify(convListener).onBlipAdded(second); verifyNoMoreInteractions(blipListener, threadListener, convListener); }
/** * Tests that empty threads are not ignored. */ public void testCreateWithEmptyManifestThreadNotIgnored() { ConversationBlip blip = target.getRootThread().appendBlip(); ConversationThread thread = blip.addReplyThread(); WaveletBasedConversation another = mirrorConversation(target); assertNotNull(another.getRootThread().getFirstBlip()); assertTrue(another.getRootThread().getFirstBlip().getReplyThreads().iterator().hasNext()); }
/** * Test that we can cope with blips being added to the manifest but not to the * wavelet. */ public void testAddingBlipMissingFromWavelet() { manifestDoc.with(new Action() { @Override public <N, E extends N, T extends N> void exec(MutableDocument<N, E, T> doc) { N rootThreadNode = doc.getFirstChild(doc.getDocumentElement()); E rootThread = doc.asElement(rootThreadNode); doc.createChildElement(rootThread, "blip", Collections.singletonMap( "id", idGenerator.newBlipId())); } }); assertNull(target.getRootThread().getFirstBlip()); assertEquals(Collections.emptyList(), getBlipList(target.getRootThread())); }
WaveletBasedConversation rootConv = makeConversation(); WaveletBasedConversationBlip rootWaveletRootBlip = rootConv.getRootThread().appendBlip(); assertManifestXml( "<blip id=\"" + firstBlip.getId() + "\">" + "<thread id=\"" + firstReply.getId() + "\">" + "</blip>" + "<blip id=\"" + secondBlip.getId() + "\"></blip>"); assertMirrorConversationEquivalent();
public void testAbstractBlipIdMatchesConcreteBlipId() { populate(target); WaveletBasedConversationBlip convBlip = target.getRootThread().getFirstBlip(); assertEquals(convBlip.getId(), convBlip.getBlip().getId()); }
public void testGetBlipRetrievesBlip() { WaveletBasedConversationBlip blip = target.getRootThread().appendBlip(); WaveletBasedConversationThread reply = blip.addReplyThread(); WaveletBasedConversationBlip replyBlip = reply.appendBlip(); assertSame(blip, target.getBlip(blip.getId())); assertSame(replyBlip, target.getBlip(replyBlip.getId())); assertNull(target.getBlip("foobar")); }
public void testDeleteLastBlipInThreadRemovesThread() { ConversationBlip rootBlip = target.getRootThread().appendBlip(); ConversationThread topThread = rootBlip.addReplyThread(); ConversationBlip topBlip = topThread.appendBlip(); ConversationThread firstReply = topBlip.addReplyThread(); firstReply.appendBlip().delete(); assertNull(topBlip.getReplyThread(firstReply.getId())); assertManifestXml("<blip id=\"" + rootBlip.getId() + "\">" + "<thread id=\"" + topThread.getId() + "\">" + "<blip id=\"" + topBlip.getId() + "\"></blip>" + "</thread>" + "</blip>"); }
/** * Test that iterating a thread whose manifest contains blips not backed by the * wavelet skips those blips. */ public void testMissingBlipIteration() { WaveletBasedConversationThread thread = target.getRootThread(); WaveletBasedConversationBlip first = thread.appendBlip(); manifestDoc.with(new Action() { @Override public <N, E extends N, T extends N> void exec(MutableDocument<N, E, T> doc) { N rootThreadNode = doc.getFirstChild(doc.getDocumentElement()); E rootThread = doc.asElement(rootThreadNode); doc.createChildElement(rootThread, "blip", Collections.singletonMap( "id", idGenerator.newBlipId())); } }); WaveletBasedConversationBlip third = thread.appendBlip(); assertEquals(3, CollectionUtils.newArrayList(thread.getManifestThread().getBlips()).size()); assertEquals(Arrays.asList(first, third), getBlipList(thread)); }
/** * Tests that an empty manifest document means no anchor. */ public void testEmptyManifestHasNoAnchor() { assertFalse(target.hasAnchor()); }
public void testConcurrentDeletionOfFinalThreadsLeavesEmptyBlip() { WaveletBasedConversationBlip first = target.getRootThread().appendBlip(); WaveletBasedConversationThread t1 = first.addReplyThread(); WaveletBasedConversationBlip t1b = t1.appendBlip(); WaveletBasedConversationThread t2 = first.addReplyThread(); WaveletBasedConversationBlip t2b = t2.appendBlip(); // Locally delete t1, remotely delete t2. t1b.delete(); first.addListener(blipListener); t2.addListener(threadListener); target.addListener(convListener); remoteRemoveBlip(t2b); remoteRemoveThread(t2); // Expect thread t2 deletion events and it to be invalid. verify(threadListener).onDeleted(); verify(convListener).onBlipDeleted(t2b); verify(convListener).onThreadDeleted(t2); assertBlipInvalid(t2b); assertThreadInvalid(t2); assertBlipValid(first); assertNotNull(target.getRootThread().getFirstBlip()); // The manifest now has an empty blip. assertEquals(0, first.getManifestBlip().numReplies()); // Still there after next write. WaveletBasedConversationBlip second = target.getRootThread().appendBlip(); assertBlipValid(first); verify(convListener).onBlipAdded(second); verifyNoMoreInteractions(blipListener, threadListener, convListener); }
/** * Tests that setting an anchor updates the conversation manifest correctly. */ public void testSetAnchorUpdatesManifest() { // Anchor target(wavelet1) in alternate (wavelet2). WaveletBasedConversation conversation2 = makeConversation(); populate(conversation2); ConversationBlip firstBlip = getFirstBlip(conversation2); Anchor anchor = conversation2.createAnchor(firstBlip); target.setAnchor(anchor); assertEquals(WaveletBasedConversation.idFor(conversation2.getWavelet().getId()), getManifestAttribute(manifestDoc, "anchorWavelet")); assertEquals(firstBlip.getId(), getManifestAttribute(manifestDoc, "anchorBlip")); }