/** * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.waveprotocol.wave.model.supplement; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import junit.framework.TestCase; import org.waveprotocol.wave.model.conversation.Blips; import org.waveprotocol.wave.model.conversation.ConversationBlip; import org.waveprotocol.wave.model.conversation.ObservableConversationThread; import org.waveprotocol.wave.model.conversation.WaveletBasedConversation; import org.waveprotocol.wave.model.conversation.testing.FakeConversationView; import org.waveprotocol.wave.model.id.IdGenerator; import org.waveprotocol.wave.model.id.IdUtil; import org.waveprotocol.wave.model.id.WaveletId; import org.waveprotocol.wave.model.schema.SchemaCollection; import org.waveprotocol.wave.model.schema.account.AccountSchemas; import org.waveprotocol.wave.model.schema.conversation.ConversationSchemas; import org.waveprotocol.wave.model.schema.supplement.UserDataSchemas; import org.waveprotocol.wave.model.supplement.SupplementedWaveImpl.DefaultFollow; import org.waveprotocol.wave.model.testing.FakeIdGenerator; 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.Wavelet; import java.util.Arrays; import java.util.Collections; import java.util.Map; import java.util.Set; /** * Tests for {@link SupplementedWaveImpl}. * */ public final class SupplementedWaveImplTest extends TestCase { /** * Stub for a wave view, exposing versioned wavelets, and allowing version * increments. */ private static class StubSupplementWaveView implements SupplementWaveView { private final Map<WaveletId, Long> versions = CollectionUtils.newHashMap(); private final Map<WaveletId, Map<String, Long>> blipVersions = CollectionUtils.newHashMap(); private boolean isExplicitParticipant; @Override public long getVersion(WaveletId id) { return versions.get(id); } @Override public HashedVersion getSignature(WaveletId id) { return HashedVersion.unsigned(0); } @Override public Iterable<WaveletId> getWavelets() { return versions.keySet(); } @Override public Map<String, Long> getBlipVersions(WaveletId id) { return blipVersions.get(id); } @Override public boolean isExplicitParticipant() { return isExplicitParticipant; } public void put(WaveletId id, long version) { versions.put(id, version); } public void putBlipVersion(WaveletId id, String blipId, long version) { Map<String, Long> waveletBlipVersions = blipVersions.get(id); if (waveletBlipVersions == null) { waveletBlipVersions = CollectionUtils.newHashMap(); blipVersions.put(id, waveletBlipVersions); } waveletBlipVersions.put(blipId, version); } /** Increments the version of a wavelet. */ public void touch(WaveletId id) { if (versions.containsKey(id)) { versions.put(id, versions.get(id) + 1); } } } private static final SchemaCollection schemas = new SchemaCollection(); static { schemas.add(new AccountSchemas()); schemas.add(new ConversationSchemas()); schemas.add(new UserDataSchemas()); } private static final WaveletId ROOT; private static final String ROOT_BLIP1; private static final WaveletId W1; private static final String W1_BLIP1; private static final long ROOT_VERSION = 30; private static final long ROOT_BLIP1_VERSION = 28; private static final long W1_VERSION = 20; private static final long W1_BLIP1_VERSION = 15; private final static Map<WaveletId, Long> EXPECTED_ARCHIVE_VERSIONS; static { IdGenerator generator = FakeIdGenerator.create(); ROOT = generator.newConversationRootWaveletId(); W1 = generator.newConversationWaveletId(); ROOT_BLIP1 = generator.newBlipId(); W1_BLIP1 = generator.newBlipId(); EXPECTED_ARCHIVE_VERSIONS = CollectionUtils.newHashMap(); EXPECTED_ARCHIVE_VERSIONS.put(ROOT, ROOT_VERSION); EXPECTED_ARCHIVE_VERSIONS.put(W1, W1_VERSION); } private StubSupplementWaveView wave; private PrimitiveSupplement substrate; private SupplementedWave supplement; @Override protected void setUp() throws Exception { // // Initial state is: // * a wave with two wavelets in view, ROOT and W1, at particular versions. // * an empty supplement. // substrate = new PrimitiveSupplementImpl(); wave = new StubSupplementWaveView(); wave.put(ROOT, ROOT_VERSION); wave.put(W1, W1_VERSION); wave.putBlipVersion(ROOT, ROOT_BLIP1, ROOT_BLIP1_VERSION); wave.putBlipVersion(W1, W1_BLIP1, W1_BLIP1_VERSION); supplement = SupplementedWaveImpl.create(substrate, wave, DefaultFollow.ALWAYS); } private void createEmptyWave() { substrate = new PrimitiveSupplementImpl(); wave = new StubSupplementWaveView(); supplement = SupplementedWaveImpl.create(substrate, wave, DefaultFollow.ALWAYS); } /** * Sets up the test supplement with a real wave model behind it. */ private WaveletBasedConversation setUpWithWaveModel() { FakeConversationView view = FakeConversationView.builder().with(schemas).build(); WaveletBasedConversation conversation = view.createRoot(); ParticipantId viewer = new ParticipantId("nobody@nowhere.com"); supplement = SupplementedWaveImpl.create(substrate, view, viewer, DefaultFollow.ALWAYS); return conversation; } private void addTags(Wavelet wavelet) { wavelet.getDocument(IdUtil.TAGS_DOC_ID); } // // Environment tests. // public void testIncorrectExternalWaveViewThrowsException() { // Make view return a non-conversational id, and test that supplement actions throw exceptions. wave.put(FakeIdGenerator.create().newUserDataWaveletId("foo@bar.com"), 20); try { supplement.archive(); fail(); } catch (RuntimeException e) { // expected } try { supplement.markAsRead(); fail(); } catch (RuntimeException e) { // expected } } // // Read/unread tests. // public void testNewBlipIsUnread() { WaveletBasedConversation c = setUpWithWaveModel(); ObservableConversationThread t = c.getRootThread(); ConversationBlip b = t.appendBlip(); assertTrue(supplement.isUnread(b)); } public void testMarkBlipAsReadAffectsBlipReadState() { WaveletBasedConversation c = setUpWithWaveModel(); ObservableConversationThread t = c.getRootThread(); ConversationBlip b = t.appendBlip(); supplement.markAsRead(b); assertFalse(supplement.isUnread(b)); } public void testMarkBlipIsIdempotent() { // Use real wave-model view. WaveletBasedConversation c = setUpWithWaveModel(); Wavelet w = c.getWavelet(); ObservableConversationThread t = c.getRootThread(); ConversationBlip b = t.appendBlip(); supplement.markAsRead(b); int blipReadVersion = substrate.getLastReadBlipVersion(w.getId(), b.getId()); int waveletVersion = (int) w.getVersion(); assertEquals(waveletVersion, blipReadVersion); // Do something to increase wavelet version without increasing blip last-modified version. t.appendBlip(); assert w.getVersion() > waveletVersion : "test wave model did not increase version"; // Test that marking blip as read again has no effect. supplement.markAsRead(b); long newBlipReadVersion = substrate.getLastReadBlipVersion(w.getId(), b.getId()); assertEquals(blipReadVersion, (int) newBlipReadVersion); } public void testMarkingBlipAsReadAfterWaveUnreadMarksAtWaveletVersion() { // Mark blip as read, then mark wavelet as unread, then mark blip as read // again, and test that it is marked at wavelet version. There is no real // design reason to test this use case; this is just here because it was a // specific case that was failing before. WaveletBasedConversation c = setUpWithWaveModel(); Wavelet w = c.getWavelet(); ObservableConversationThread t = c.getRootThread(); ConversationBlip b = t.appendBlip(); supplement.markAsRead(b); supplement.markAsUnread(); // Do something to increase wavelet version without increasing blip last-modified version. t.appendBlip(); // Mark as read again, test that it's marked at wavelet version. supplement.markAsRead(b); int blipReadVersion = substrate.getLastReadBlipVersion(w.getId(), b.getId()); assertEquals(blipReadVersion, (int) w.getVersion()); } public void testMarkingBlipAsReadAfterBlipModifiedMarksAtWaveletVersion() { // Mark blip as read, then mark wavelet as unread, then mark blip as read // again, and test that it is marked at wavelet version. There is no real // design reason to test this use case; this is just here because it was a // specific case that was failing before. WaveletBasedConversation c = setUpWithWaveModel(); Wavelet w = c.getWavelet(); ObservableConversationThread t = c.getRootThread(); ConversationBlip b = t.appendBlip(); supplement.markAsRead(b); supplement.markAsUnread(); // Increase both last-modified blip version and wavelet version (but latter more than former). b.getContent().appendXml(Blips.INITIAL_CONTENT); t.appendBlip(); // Mark as read again, test that it's marked at wavelet version, not blip last-modified version. supplement.markAsRead(b); long blipReadVersion = substrate.getLastReadBlipVersion(w.getId(), b.getId()); assertEquals(blipReadVersion, (int) w.getVersion()); } // // Wave state tests (inbox / archive / mute). // private void assertIsInbox() { assertTrue(supplement.isInbox()); assertFalse(supplement.isArchived()); assertFalse(supplement.isMute()); } private void assertIsArchived() { assertFalse(supplement.isInbox()); assertTrue(supplement.isArchived()); assertFalse(supplement.isMute()); } private void assertIsUnfollowed() { assertFalse(supplement.isInbox()); assertFalse(supplement.isArchived()); assertTrue(supplement.isMute()); } public void testUnmutedUnarchivedIsInbox() { assertIsInbox(); } public void testEmptyWaveState() { createEmptyWave(); assertIsArchived(); } public void testUnmutedSomeArchivedIsInbox() { substrate.archiveAtVersion(ROOT, (int) ROOT_VERSION); assertIsInbox(); } public void testUnmutedArchivedIsNotInbox() { supplement.archive(); assertIsArchived(); } public void testUnmutedRemoteArchivedIsNotInbox() { substrate.archiveAtVersion(ROOT, (int) ROOT_VERSION); substrate.archiveAtVersion(W1, (int) W1_VERSION); assertIsArchived(); } public void testUnfollowedIsNotInbox() { supplement.unfollow(); assertIsUnfollowed(); } public void testRemoteUnfollowedIsNotInbox() { substrate.unfollow(); assertIsUnfollowed(); } public void testArchiveArchivesAllWavelets() { supplement.archive(); assertSubstrateArchiveVersionsEquals(EXPECTED_ARCHIVE_VERSIONS); assertIsArchived(); } public void testChangeAfterArchiveIsInbox() { supplement.archive(); wave.touch(ROOT); assertIsInbox(); } public void testChangeAfterUnfollowIsNotInbox() { supplement.unfollow(); wave.touch(ROOT); assertIsUnfollowed(); } public void testUnfollowUnfollowsSubstrate() { supplement.unfollow(); assertEquals(Boolean.FALSE, substrate.getFollowed()); assertIsUnfollowed(); } public void testMuteClearsArchiveVersions() { supplement.archive(); supplement.mute(); assertSubstrateArchiveVersionsEquals(Collections.<WaveletId, Long>emptyMap()); } public void testArchiveDoesNotClearMuteNorSetsArchiveVersions() { supplement.unfollow(); supplement.archive(); assertEquals(Boolean.FALSE, substrate.getFollowed()); assertSubstrateArchiveVersionsEquals(Collections.<WaveletId, Long> emptyMap()); } // // Folder tests. // public void testMoveToFolderArchives() { supplement.moveToFolder(100); assertSubstrateArchiveVersionsEquals(EXPECTED_ARCHIVE_VERSIONS); } public void testMoveToFolderRemovesExistingFolders() { substrate.addFolder(100); substrate.addFolder(101); supplement.moveToFolder(102); assertEquals(supplement.getFolders(), Collections.singleton(102)); assertSubstrateFoldersEquals(Collections.singleton(102)); } public void testMoveToFolderIsNotInbox() { supplement.moveToFolder(100); assertFalse(supplement.isInbox()); } public void testMoveToFolderPreservesUnfollow() { supplement.unfollow(); supplement.moveToFolder(100); assertEquals(Boolean.FALSE, substrate.getFollowed()); } public void testMoveToInboxFolderMovesToInbox() { supplement.moveToFolder(SupplementedWaveImpl.INBOX_FOLDER); assertTrue(supplement.isInbox()); assertSubstrateFoldersEquals(Collections.<Integer>emptySet()); } public void testMoveToInboxFolderRemovesExistingFolders() { supplement.moveToFolder(100); supplement.moveToFolder(SupplementedWaveImpl.INBOX_FOLDER); assertEquals(Collections.emptySet(), supplement.getFolders()); } public void testInboxMovesToInbox() { supplement.inbox(); assertIsInbox(); } public void testInboxClearsArchiveState() { supplement.archive(); supplement.inbox(); assertSubstrateArchiveVersionsEquals(Collections.<WaveletId, Long>emptyMap()); } public void testMoveToFolderAllArchivesAndClearsFolderState() { supplement.moveToFolder(100); supplement.moveToFolder(SupplementedWaveImpl.ALL_FOLDER); assertIsArchived(); assertEquals(Collections.emptySet(), supplement.getFolders()); assertSubstrateArchiveVersionsEquals(EXPECTED_ARCHIVE_VERSIONS); assertSubstrateFoldersEquals(Collections.<Integer>emptySet()); } public void testMoveToFolderAllPreservesMute() { supplement.moveToFolder(100); supplement.unfollow(); supplement.moveToFolder(SupplementedWaveImpl.ALL_FOLDER); assertEquals(Boolean.FALSE, substrate.getFollowed()); } public void testMutePreservesFolders() { supplement.moveToFolder(100); supplement.mute(); assertEquals(Collections.singleton(100), supplement.getFolders()); } public void testParticipantReadState() { WaveletBasedConversation c = setUpWithWaveModel(); Wavelet w = c.getWavelet(); assertFalse(supplement.haveParticipantsEverBeenRead(w)); assertTrue(supplement.isParticipantsUnread(w)); supplement.markParticipantAsRead(w); assertTrue(supplement.haveParticipantsEverBeenRead(w)); assertFalse(supplement.isParticipantsUnread(w)); } public void testParticipantReadStateWithBlip() { WaveletBasedConversation c = setUpWithWaveModel(); ObservableConversationThread t = c.getRootThread(); ConversationBlip b = t.appendBlip(); supplement.markParticipantAsRead(c.getWavelet()); } public void testParticipantReadStateAffectedByWaveletReadState() { WaveletBasedConversation c = setUpWithWaveModel(); Wavelet w = c.getWavelet(); assertFalse(supplement.haveParticipantsEverBeenRead(w)); assertTrue(supplement.isParticipantsUnread(w)); supplement.markAsRead(); assertTrue(supplement.haveParticipantsEverBeenRead(w)); assertFalse(supplement.isParticipantsUnread(w)); } public void testSeeMarksAsSeenAtVersion() { PrimitiveSupplement primitiveSupplement = mock(PrimitiveSupplement.class); SupplementWaveView supplementedView = mock(SupplementWaveView.class); final HashedVersion signature1 = HashedVersion.of(234L, new byte[] { 1 }), signature2 = HashedVersion.of(12828L, new byte[] { 2 }); WaveletId waveletId1 = WaveletId.of("example.com", "somewaveletid1"); when(supplementedView.getSignature(waveletId1)).thenReturn(signature1); WaveletId waveletId2 = WaveletId.of("example.com", "somewaveletid2"); when(supplementedView.getSignature(waveletId2)).thenReturn(signature2); when(supplementedView.getWavelets()).thenReturn(Arrays.asList(waveletId1, waveletId2)); SupplementedWaveImpl supplementedWave = new SupplementedWaveImpl( primitiveSupplement, supplementedView, DefaultFollow.ALWAYS); supplementedWave.see(); verify(primitiveSupplement).setSeenVersion(eq(waveletId1), eq(signature1)); verify(primitiveSupplement).setSeenVersion(eq(waveletId2), eq(signature2)); // simulate the balancing get for the set we just verified above. when(primitiveSupplement.getSeenVersion(waveletId1)).thenReturn(signature1); when(primitiveSupplement.getSeenVersion(waveletId2)).thenReturn(signature2); assertEquals(signature1, supplementedWave.getSeenVersion(waveletId1)); assertEquals(signature2, supplementedWave.getSeenVersion(waveletId2)); } public void testGetSeenVersionReturnsSeenSignature() { PrimitiveSupplement primitiveSupplement = mock(PrimitiveSupplement.class); SupplementWaveView supplementedView = mock(SupplementWaveView.class); WaveletId waveletId1 = WaveletId.of("example.com", "somewaveletid1"); HashedVersion wavelet1SeenVersion = HashedVersion.of(12312L, new byte[] { 1 }); when(supplementedView.getWavelets()).thenReturn(Arrays.asList(waveletId1)); when(primitiveSupplement.getSeenVersion(waveletId1)).thenReturn( wavelet1SeenVersion); SupplementedWaveImpl supplementedWave = new SupplementedWaveImpl( primitiveSupplement, supplementedView, DefaultFollow.ALWAYS); assertEquals(wavelet1SeenVersion, supplementedWave.getSeenVersion(waveletId1)); } public void testTrashedIfWaveInTrash() { PrimitiveSupplement primitiveSupplement = mock(PrimitiveSupplement.class); SupplementWaveView supplementedView = mock(SupplementWaveView.class); when(primitiveSupplement.getFolders()) .thenReturn(Arrays.asList(SupplementedWaveImpl.TRASH_FOLDER)); assertTrue(new SupplementedWaveImpl( primitiveSupplement, supplementedView,DefaultFollow.ALWAYS) .isTrashed()); } public void testNotTrashedIfWaveIsNotInTrash() { PrimitiveSupplement primitiveSupplement = mock(PrimitiveSupplement.class); SupplementWaveView supplementedView = mock(SupplementWaveView.class); when(primitiveSupplement.getFolders()) .thenReturn(Arrays.asList(SupplementedWaveImpl.INBOX_FOLDER)); assertFalse(new SupplementedWaveImpl(primitiveSupplement, supplementedView, DefaultFollow.ALWAYS) .isTrashed()); } public void testHasBeenSeen() { PrimitiveSupplement primitiveSupplement = mock(PrimitiveSupplement.class); SupplementWaveView supplementedView = mock(SupplementWaveView.class); final HashedVersion signature1 = HashedVersion.of(234L, new byte[] { 1 }); WaveletId waveletId1 = WaveletId.of("google.com", "somewaveletid1"); when(supplementedView.getSignature(waveletId1)).thenReturn(signature1); when(supplementedView.getWavelets()).thenReturn(Arrays.asList(waveletId1)); SupplementedWave supplementedWave = new SupplementedWaveImpl(primitiveSupplement, supplementedView, DefaultFollow.ALWAYS); assertFalse(supplementedWave.hasBeenSeen()); supplementedWave.see(); verify(primitiveSupplement).setSeenVersion(eq(waveletId1), eq(signature1)); when(primitiveSupplement.getSeenVersion(waveletId1)).thenReturn(signature1); assertTrue(supplementedWave.hasBeenSeen()); } public void testReadStateAffectedByTagsState() { WaveletBasedConversation c = setUpWithWaveModel(); Wavelet w = c.getWavelet(); assertTrue(supplement.isTagsUnread(w)); addTags(w); assertTrue(supplement.isTagsUnread(w)); supplement.markAsRead(); assertFalse(supplement.isTagsUnread(w)); supplement.markAsUnread(); assertTrue(supplement.isTagsUnread(w)); supplement.markTagsAsRead(w); assertFalse(supplement.isTagsUnread(w)); } public void testParticipantReadStateAffectedByWaveletReadStateWithBlip() { WaveletBasedConversation c = setUpWithWaveModel(); ObservableConversationThread t = c.getRootThread(); ConversationBlip b = t.appendBlip(); supplement.markAsRead(); } public void testNewWaveHasNoPendingNotification() { assertFalse(supplement.hasPendingNotification()); } public void testReportsPendingNotification() { substrate.setNotifiedVersion(W1, (int) W1_VERSION); assertTrue(supplement.hasPendingNotification()); } public void testSeeingClearsPendingNotification() { PrimitiveSupplement primitiveSupplement = mock(PrimitiveSupplement.class); SupplementWaveView supplementedView = mock(SupplementWaveView.class); final byte[] SIGNATURE = new byte[] { 1 }; final long VERSION_1 = 234L; final long VERSION_2 = 12828L; final HashedVersion signature1 = HashedVersion.of(VERSION_1, SIGNATURE), signature2 = HashedVersion.of(VERSION_2, SIGNATURE); WaveletId waveletId1 = WaveletId.of("example.com", "somewaveletid1"); when(supplementedView.getSignature(waveletId1)).thenReturn(signature1); WaveletId waveletId2 = WaveletId.of("example.com", "somewaveletid2"); when(supplementedView.getSignature(waveletId2)).thenReturn(signature2); when(supplementedView.getWavelets()).thenReturn(Arrays.asList(waveletId1, waveletId2)); when(primitiveSupplement.getNotifiedWavelets()) .thenReturn(CollectionUtils.immutableSet(waveletId1, waveletId2)); when(primitiveSupplement.getSeenVersion(waveletId1)) .thenReturn(HashedVersion.unsigned(0)).thenReturn(signature1); when(primitiveSupplement.getSeenVersion(waveletId2)).thenReturn(signature2); when(supplementedView.getVersion(waveletId1)).thenReturn(VERSION_1); when(supplementedView.getVersion(waveletId2)).thenReturn(VERSION_2); when(primitiveSupplement.getNotifiedVersion(waveletId1)).thenReturn((int) VERSION_1); when(primitiveSupplement.getNotifiedVersion(waveletId2)).thenReturn((int) VERSION_2); SupplementedWaveImpl supplementedWave = new SupplementedWaveImpl( primitiveSupplement, supplementedView, DefaultFollow.ALWAYS); supplementedWave.markAsNotified(); verify(primitiveSupplement).setNotifiedVersion(eq(waveletId1), eq((int) VERSION_1)); verify(primitiveSupplement).setNotifiedVersion(eq(waveletId2), eq((int) VERSION_2)); assertTrue(supplementedWave.hasPendingNotification()); supplementedWave.see(); // Clears the deprecated pending-notification flag. verify(primitiveSupplement).clearPendingNotification(); assertFalse(supplementedWave.hasPendingNotification()); } public void testSeeingClearsPendingNotification_pendingNotificationFlagSet() { PrimitiveSupplement primitiveSupplement = mock(PrimitiveSupplement.class); SupplementWaveView supplementedView = mock(SupplementWaveView.class); final byte[] SIGNATURE = new byte[] { 1 }; final long VERSION_1 = 234L; final HashedVersion signature1 = HashedVersion.of(VERSION_1, SIGNATURE); WaveletId waveletId1 = WaveletId.of("example.com", "somewaveletid1"); when(supplementedView.getSignature(waveletId1)).thenReturn(signature1); when(primitiveSupplement.getNotifiedWavelets()) .thenReturn(CollectionUtils.<WaveletId>immutableSet()) .thenReturn(CollectionUtils.immutableSet(waveletId1)); when(supplementedView.getWavelets()).thenReturn(Arrays.asList(waveletId1)); // There is a legacy pending notification flag set. when(primitiveSupplement.getPendingNotification()).thenReturn(true); SupplementedWaveImpl supplementedWave = new SupplementedWaveImpl( primitiveSupplement, supplementedView, DefaultFollow.ALWAYS); assertTrue(supplementedWave.hasPendingNotification()); when(primitiveSupplement.getSeenVersion(waveletId1)) .thenReturn(HashedVersion.unsigned(0)).thenReturn(signature1); when(supplementedView.getVersion(waveletId1)).thenReturn(VERSION_1); when(primitiveSupplement.getNotifiedVersion(waveletId1)).thenReturn((int) VERSION_1); supplementedWave.markAsNotified(); verify(primitiveSupplement).setNotifiedVersion(eq(waveletId1), eq((int) VERSION_1)); assertTrue(supplementedWave.hasPendingNotification()); supplementedWave.see(); // Clears the deprecated pending-notification flag. verify(primitiveSupplement).clearPendingNotification(); assertFalse(supplementedWave.hasPendingNotification()); } // // Test helpers. // /** * Checks the archive versions in the supplement substrate. * * @param expected expected archive versions */ private void assertSubstrateArchiveVersionsEquals(Map<WaveletId, Long> expected) { Map<WaveletId, Long> actual = CollectionUtils.newHashMap(); for (WaveletId wid : substrate.getArchiveWavelets()) { actual.put(wid, (long) substrate.getArchiveWaveletVersion(wid)); } assertEquals(expected, actual); } /** * Checks the folders in the supplement substrate. * * @param expected */ private void assertSubstrateFoldersEquals(Set<Integer> expected) { Set<Integer> actual = CollectionUtils.newHashSet(); for (Integer folder : substrate.getFolders()) { actual.add(folder); } assertEquals(expected, actual); } }