// BlogBridge -- RSS feed reader, manager, and web based service // Copyright (C) 2002-2006 by R. Pito Salas // // This program is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free Software Foundation; // either version 2 of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along with this program; // if not, write to the Free Software Foundation, Inc., 59 Temple Place, // Suite 330, Boston, MA 02111-1307 USA // // Contact: R. Pito Salas // mailto:pitosalas@users.sourceforge.net // More information: about BlogBridge // http://www.blogbridge.com // http://sourceforge.net/projects/blogbridge // // $Id: TestSyncIn.java,v 1.33 2007/02/07 15:33:43 spyromus Exp $ // package com.salas.bb.service.sync; import com.jgoodies.uif.application.Application; import com.jgoodies.uif.application.ApplicationConfiguration; import com.jgoodies.uif.util.ResourceUtils; import com.salas.bb.domain.*; import com.salas.bb.domain.query.ICriteria; import com.salas.bb.domain.query.articles.ArticleTextProperty; import com.salas.bb.domain.query.articles.Query; import com.salas.bb.domain.query.general.StringEqualsCO; import com.salas.bb.domain.querytypes.QueryType; import junit.framework.TestCase; import java.net.MalformedURLException; import java.net.URL; import java.util.ResourceBundle; /** * @see SyncIn */ public class TestSyncIn extends TestCase { private GuidesSet local; private GuidesSet remote; static { Application.setConfiguration(new ApplicationConfiguration( "bb/test", // Root node for prefs and logs "", // resource.properties URL "docs/Help.hs", // Helpset URL "docs/tips/index.txt")); ResourceUtils.setBundle(ResourceBundle.getBundle("Resource")); } protected void setUp() throws Exception { super.setUp(); local = new GuidesSet(); remote = new GuidesSet(); } // Evaluate changes ---------------------------------------------------------------------------- /** * Test a guide and a feed added remotely. */ public void testAddedRemotely() { // local is empty, remote has one guide and one feed StandardGuide guide = guide("a"); DirectFeed feed = directFeed(1); guide.add(feed); remote.add(guide); // --- Checking SyncIn.Changes changes = SyncIn.evaluateChanges(local, remote, false); assertChanges(changes, 0, 0, 1, 0); assertTrue(feed == changes.getAddFeeds().get(0)); } /** * Tests comparing equal layouts. Local and remote feeds are the same. */ public void testLocalIsTheSame() { // local StandardGuide guide1 = guide("a"); guide1.add(directFeed(1)); local.add(guide1); StandardGuide guide2 = guide("b"); guide2.add(directFeed(2)); guide2.add(queryFeed(2)); guide2.add(searchFeed(2)); local.add(guide2); // remote StandardGuide guide1r = guide("a"); guide1r.add(directFeed(1)); remote.add(guide1r); StandardGuide guide2r = guide("b"); guide2r.add(directFeed(2)); guide2r.add(queryFeed(2)); guide2r.add(searchFeed(2)); remote.add(guide2r); // --- Checking SyncIn.Changes changes = SyncIn.evaluateChanges(local, remote, false); assertChanges(changes, 0, 0, 0, 0); } /** * The feed has already been known to the service and was removed * remotely. */ public void testRemovedRemotelySync() { // local StandardGuide guide1 = guide("a"); DirectFeed feed = directFeed(1); addAndMarkAsSynced(guide1, feed); local.add(guide1); // remote remote.add(guide("a")); // --- Checking SyncIn.Changes changes = SyncIn.evaluateChanges(local, remote, false); assertChanges(changes, 0, 0, 0, 1); assertRemoveFeed(guide1, feed, changes, 0); } /** * Tests the case when user adds a feed locally between two synchronizations. * The application suggests no removal because it knows that the feed was * added. */ public void testAddedLocally() { // local StandardGuide guide1 = guide("a"); DirectFeed feed = directFeed(1); guide1.add(feed); local.add(guide1); // remote remote.add(guide("a")); // --- Checking SyncIn.Changes changes = SyncIn.evaluateChanges(local, remote, false); assertChanges(changes, 0, 0, 0, 0); } /** * Tests the case when user adds a feed locally between two synchronizations. * The application suggests removal of the local feed as we wish to copy the service layout. */ public void testAddedLocallyCopyService() { // local StandardGuide guide1 = guide("a"); DirectFeed feed = directFeed(1); guide1.add(feed); local.add(guide1); // remote remote.add(guide("a")); // --- Checking SyncIn.Changes changes = SyncIn.evaluateChanges(local, remote, true); assertChanges(changes, 0, 0, 0, 1); } /** * There was a guide with one feed and it has been removed remotely. */ public void testRemovedGuideRemotely() { // local StandardGuide guide1 = guide("a"); DirectFeed feed = directFeed(1); addAndMarkAsSynced(guide1, feed); local.add(guide1); // --- Checking SyncIn.Changes changes = SyncIn.evaluateChanges(local, remote, false); assertChanges(changes, 0, 0, 0, 1); } /** * When one feed is removed from the guide and the similar feed is added * to the other guide, we would better reuse the feed instead of flushing * read states and other info. */ public void testRepositioning() { // local StandardGuide guide1 = guide("a"); DirectFeed feed = directFeed(1); addAndMarkAsSynced(guide1, feed); local.add(guide1); // remote StandardGuide guide2 = guide("b"); DirectFeed feed2 = directFeed(1); addAndMarkAsSynced(guide2, feed2); remote.add(guide2); // --- Checking SyncIn.Changes changes = SyncIn.evaluateChanges(local, remote, false); assertChanges(changes, 0, 0, 1, 1); } // Evaluate Changes within Guide Feeds --------------------------------------------------------- /** * Tests detection of a feed added remotely. */ public void testECFAddedRemotely() { SyncIn.Changes changes = new SyncIn.Changes(); StandardGuide local = guide("a"); StandardGuide remote = guide("a"); remote.add(directFeed(1)); remote.add(queryFeed(1)); remote.add(searchFeed(1)); // --- Checking SyncIn.evaluateChangesInGuide(local, remote, changes, false); assertChanges(changes, 0, 0, 3, 0); } /** * Testing how guide properties are transferred when adding or updating guide. * * NOTE: Use this test to check how the properties are transferred when adding a new guide or updating * from the service. */ public void testTransferGuideProperties() { StandardGuide pattern = new StandardGuide(); pattern.setPublishingRating(3); // Creating guide from remote pattern StandardGuide guide = new StandardGuide(); SyncIn.transferGuideProperties(guide, pattern); assertEquals(pattern.getPublishingRating(), guide.getPublishingRating()); } /** * Tests detection of a feed added remotely (checking properties transfer). */ public void testECFAddedRemotelyPropertiesTransfer() { SyncIn.Changes changes = new SyncIn.Changes(); // Empty local StandardGuide localG = guide("a"); local.add(localG); // 3 Feeds remotely StandardGuide remoteG = guide("a"); DirectFeed dFeed = directFeed(1); dFeed.setPinnedArticlesKeys("a,b"); QueryFeed qFeed = queryFeed(1); qFeed.setPinnedArticlesKeys("c,d"); SearchFeed sFeed = searchFeed(1); remoteG.add(dFeed); remoteG.add(qFeed); remoteG.add(sFeed); // --- Checking SyncIn.evaluateChangesInGuide(localG, remoteG, changes, false); SyncIn.performChanges(local, changes, null); IFeed[] lFeeds = localG.getFeeds(); assertFeed(dFeed, qFeed, lFeeds[0]); assertFeed(dFeed, qFeed, lFeeds[1]); assertFeed(dFeed, qFeed, lFeeds[2]); } /** * Checks how the properties match depending on the type of the feed. * * @param dFeed direct feed to check against if the target is of DirectFeed type. * @param qFeed query feed to check against if the target is of QueryFeed type. * @param target target feed. */ private void assertFeed(DirectFeed dFeed, QueryFeed qFeed, IFeed target) { if (target instanceof DirectFeed) { assertEquals(dFeed.getPinnedArticlesKeys(), ((DirectFeed)target).getPinnedArticlesKeys()); } else if (target instanceof QueryFeed) { assertEquals(qFeed.getPinnedArticlesKeys(), ((QueryFeed)target).getPinnedArticlesKeys()); } } /** * Tests detection of a feed added locally. */ public void testECFAddedLocally() { SyncIn.Changes changes = new SyncIn.Changes(); StandardGuide local = guide("a"); local.add(directFeed(1)); local.add(queryFeed(1)); local.add(searchFeed(1)); StandardGuide remote = guide("a"); // --- Checking SyncIn.evaluateChangesInGuide(local, remote, changes, false); assertChanges(changes, 0, 0, 0, 0); } /** * Tests detection of a feed removed remotely. */ public void testECFRemovedRemotely() { SyncIn.Changes changes = new SyncIn.Changes(); StandardGuide local = guide("a"); addAndMarkAsSynced(local, directFeed(1)); addAndMarkAsSynced(local, queryFeed(1)); addAndMarkAsSynced(local, searchFeed(1)); StandardGuide remote = guide("a"); // --- Checking SyncIn.evaluateChangesInGuide(local, remote, changes, false); assertChanges(changes, 0, 0, 0, 3); } /** * Tests removal of new feeds added only locally. */ public void testECFAddedLocallyClearNew() { SyncIn.Changes changes = new SyncIn.Changes(); StandardGuide local = guide("a"); local.add(directFeed(1)); local.add(queryFeed(1)); local.add(searchFeed(1)); StandardGuide remote = guide("a"); // --- Checking SyncIn.evaluateChangesInGuide(local, remote, changes, true); assertChanges(changes, 0, 0, 0, 3); } // Reading Lists ------------------------------------------------------------------------------- /** * A guide with reading list has been added remotely. */ public void testRLAddedGuideRemotely() { // remote: one guide, one reading list, one feed StandardGuide guide = guide("a"); remote.add(guide); ReadingList list = readingList(1); guide.add(list); DirectFeed feed = directFeed(1); list.add(feed); // --- Checking SyncIn.Changes changes = SyncIn.evaluateChanges(local, remote, false); assertChanges(changes, 1, 0, 0, 0); } /** * A reading list has been added to a guide remotely. The reading list has one feed * and we add this feed as well as the reading list record. */ public void testRLAddedRemotely() { // local: one guide, one feed StandardGuide guideL = guide("a"); local.add(guideL); DirectFeed feedL = directFeed(0); addAndMarkAsSynced(guideL, feedL); // remote: one guide, one reading list, two feeds (one new) StandardGuide guideR = guide("a"); remote.add(guideR); ReadingList list = readingList(1); guideR.add(list); DirectFeed feedR = directFeed(1); list.add(feedR); guideR.add(directFeed(0)); // --- Checking SyncIn.Changes changes = SyncIn.evaluateChanges(local, remote, false); assertChanges(changes, 1, 0, 0, 0); } /** * Testing the situation when reading list has been removed remotely. */ public void testRLRemovedRemotely() { // local: one guide, one feed StandardGuide guideL = guide("a"); local.add(guideL); ReadingList list = readingList(1, true); guideL.add(list); DirectFeed feedL = directFeed(1); list.add(feedL); addAndMarkAsSynced(guideL, directFeed(0)); // remote: one guide, one reading list, two feeds (one new) StandardGuide guideR = guide("a"); remote.add(guideR); guideR.add(directFeed(0)); // --- Checking SyncIn.Changes changes = SyncIn.evaluateChanges(local, remote, false); assertChanges(changes, 0, 1, 0, 0); } /** * We test a situation when there was a guide with reading list assigned, then user * saved it to the service, renamed guide and restoring it back. * * What should happen is that we need to: create a guide with correct name, move the * reading list. */ public void testRLRenamedGuide() { // local StandardGuide guideL = guide("b"); local.add(guideL); ReadingList listL = readingList(1, true); guideL.add(listL); DirectFeed feedL = directFeed(2); listL.add(feedL); // remote StandardGuide guideR = guide("a"); remote.add(guideR); ReadingList listR = readingList(1); guideR.add(listR); DirectFeed feedR = directFeed(2); listR.add(feedR); // --- Checking SyncIn.Changes changes = SyncIn.evaluateChanges(local, remote, false); assertChanges(changes, 1, 1, 0, 0); } /** * We test a situation when there was a guide with reading list assigned, then user * saved it to the service, renamed guide and restoring it back. * * What should happen is that we need to: create a guide with correct name, move the * reading list. There's another new feed in this list recorded remotely -- we should * add it. */ public void testRLRenamedGuideNewFeed() { // local StandardGuide guideL = guide("b"); local.add(guideL); ReadingList listL = readingList(1, true); guideL.add(listL); DirectFeed feedL = directFeed(2); listL.add(feedL); // remote StandardGuide guideR = guide("a"); remote.add(guideR); ReadingList listR = readingList(1); guideR.add(listR); DirectFeed feedR = directFeed(2); listR.add(feedR); DirectFeed feedR2 = directFeed(3); listR.add(feedR2); // --- Checking SyncIn.Changes changes = SyncIn.evaluateChanges(local, remote, false); assertChanges(changes, 1, 1, 0, 0); } /** * We test a situation when there was a guide with reading list assigned, then user * saved it to the service, renamed guide and restoring it back. * * What should happen is that we need to: create a guide with correct name, move the * reading list. There were two feeds and now one of them removed -- act appropriately. */ public void testRLRenamedGuideRemovedFeed() { // local StandardGuide guideL = guide("b"); local.add(guideL); ReadingList listL = readingList(1, true); guideL.add(listL); DirectFeed feedL = directFeed(2); listL.add(feedL); DirectFeed feedL2 = directFeed(3); listL.add(feedL2); // remote StandardGuide guideR = guide("a"); remote.add(guideR); ReadingList listR = readingList(1); guideR.add(listR); DirectFeed feedR = directFeed(2); listR.add(feedR); // --- Checking SyncIn.Changes changes = SyncIn.evaluateChanges(local, remote, false); assertChanges(changes, 1, 1, 0, 0); } private void assertRemoveFeed(StandardGuide guide, DirectFeed feed, SyncIn.Changes changes, int index) { SyncIn.GuideFeedPair pair = (SyncIn.GuideFeedPair)changes.getRemoveFeeds().get(index); assertTrue(feed == pair.feed); assertTrue(guide == pair.guide); } /** * We have two guides: "a" (local) - with 2 reading lists, "b" (remote) - with static feed. * The "a" guide gets removed and "b" guide gets one similar reading list plus another feed. * Interesting part that the "b" guide has no feeds associated with reading list because it * isn't fetched yet, so the feeds associated with reading list from "a" guide should be * removed. * * The other reading list and the guide "a" should be removed. */ public void testRLReusing() { // local - reading list with two feeds StandardGuide guideL = guide("a"); local.add(guideL); ReadingList listL = readingList(1, true); guideL.add(listL); DirectFeed feedL = directFeed(2); listL.add(feedL); DirectFeed feedL2 = directFeed(3); listL.add(feedL2); // remote - reading list without feeds + static feed StandardGuide guideR = guide("b"); remote.add(guideR); ReadingList listR = readingList(1); guideR.add(listR); DirectFeed feedR = directFeed(2); guideR.add(feedR); // --- Checking SyncIn.Changes changes = SyncIn.evaluateChanges(local, remote, false); assertChanges(changes, 1, 1, 1, 0); } private static void assertChanges(SyncIn.Changes aChanges, int addRL, int removeRL, int addFeeds, int removeFeeds) { assertEquals("Wrong number of RL's to add", addRL, aChanges.getAddReadingLists().size()); assertEquals("Wrong number of RL's to remove", removeRL, aChanges.getRemoveReadingLists().size()); assertEquals("Wrong number of feeds to add", addFeeds, aChanges.getAddFeeds().size()); assertEquals("Wrong number of feeds to remove", removeFeeds, aChanges.getRemoveFeeds().size()); } // Evaluate Changes within Guide Reading Lists ------------------------------------------------- /** * A reading list is added locally, but not synchronized yet. */ public void testECRLAddedLocally() { // local - one reading list + associated feed StandardGuide guideL = guide("a"); ReadingList listL = readingList(1); guideL.add(listL); listL.add(directFeed(2)); // remote StandardGuide guideR = guide("a"); // --- Checking SyncIn.Changes changes = new SyncIn.Changes(); SyncIn.evaluateChangesInReadingLists(guideL, guideR, changes, false); assertChanges(changes, 0, 0, 0, 0); } /** * A feed is added to the reading list is added locally, but not synchronized yet. * The application should report removal when we ask to copy service layout. */ public void testECRLAddedLocallyCopyService() { // TODO This test makes sense only if we also synchronize the feed lists of RL's // local - one reading list + associated feed // StandardGuide guideL = guide("a"); // ReadingList listL = readingList(1); // guideL.add(listL); // listL.add(directFeed(1)); // listL.add(directFeed(2)); // // // remote // StandardGuide guideR = guide("a"); // ReadingList listR = readingList(1); // guideR.add(listR); // listR.add(directFeed(2)); // // // --- Checking // SyncIn.Changes changes = new SyncIn.Changes(); // SyncIn.evaluateChangesInGuide(guideL, guideR, changes, true); // assertChanges(changes, 0, 0, 0, 1); } /** * Testing that disregarding the fact that newly added reading list hasn't been synchronized * yet, it is removed because of clear-flag set. */ public void testECRLAddedLocallyClear() { // local - one reading list + associated feed StandardGuide guideL = guide("a"); ReadingList listL = readingList(1); guideL.add(listL); listL.add(directFeed(2)); // remote StandardGuide guideR = guide("a"); // --- Checking SyncIn.Changes changes = new SyncIn.Changes(); SyncIn.evaluateChangesInReadingLists(guideL, guideR, changes, true); assertChanges(changes, 0, 1, 0, 0); } /** * Testing that remotely added RL is added to the guide. */ public void testECRLAddedRemotely() { // local StandardGuide guideL = guide("a"); // remote - one reading list + associated feed StandardGuide guideR = guide("a"); ReadingList listR = readingList(1); guideR.add(listR); listR.add(directFeed(2)); // --- Checking SyncIn.Changes changes = new SyncIn.Changes(); SyncIn.evaluateChangesInReadingLists(guideL, guideR, changes, false); assertChanges(changes, 1, 0, 0, 0); } /** * Testing that remotely removed RL is marked for removal. */ public void testECRLRemovedRemotely() { // local StandardGuide guideL = guide("a"); ReadingList listL = readingList(1, true); guideL.add(listL); listL.add(directFeed(2)); // remote - one reading list + associated feed StandardGuide guideR = guide("a"); // --- Checking SyncIn.Changes changes = new SyncIn.Changes(); SyncIn.evaluateChangesInReadingLists(guideL, guideR, changes, false); assertChanges(changes, 0, 1, 0, 0); } /** * When there are two similar reading lists reported for addition from the service * and we already have at least one of them locally we shouldn't add any. */ public void testECRLLocalDuplicate() { // local StandardGuide guideL = guide("a"); ReadingList listL = readingList(1, true); guideL.add(listL); listL.add(directFeed(2)); // remote StandardGuide guideR = guide("a"); ReadingList listR = readingList(1, true); guideR.add(listR); listR.add(directFeed(2)); ReadingList listR2 = readingList(1, true); guideR.add(listR2); listR2.add(directFeed(2)); // --- Checking SyncIn.Changes changes = new SyncIn.Changes(); SyncIn.evaluateChangesInReadingLists(guideL, guideR, changes, false); assertChanges(changes, 0, 0, 0, 0); } // Resusing ------------------------------------------------------------------------------------ public void testReusing1() { // We should never reuse a feed from some reading list when removing reading list // and adding the same feed somewhere. } // Perform changes ----------------------------------------------------------------------------- /** * When the synchronization is over it may come that some guides become empty. * It happens generally because the feeds from them were moved here and there. * If it is true that the empty guide is not on remote list, it's also true * that it can be safely removed. */ public void testRemovingEmptyRedundantGuides() { // local StandardGuide guide1 = guide("a"); DirectFeed feed = directFeed(1); addAndMarkAsSynced(guide1, feed); local.add(guide1); // remote StandardGuide guide2 = guide("b"); DirectFeed feed2 = directFeed(1); addAndMarkAsSynced(guide2, feed2); remote.add(guide2); // --- Checking SyncIn.Changes changes = SyncIn.evaluateChanges(local, remote, false); SyncIn.performChanges(local, changes, null); assertEquals(1, local.getGuidesCount()); assertEquals("b", (local.getGuideAt(0)).getTitle()); } /** * Two guides with two different reading lists, but the same feeds are added. */ public void testPerformChangesRLAddedRemotely() { // remote - reading list without feeds + static feed StandardGuide guideR = guide("a"); remote.add(guideR); ReadingList listR = readingList(1); guideR.add(listR); DirectFeed feedR = directFeed(1); listR.add(feedR); StandardGuide guideR2 = guide("b"); remote.add(guideR2); ReadingList listR2 = readingList(2); guideR2.add(listR2); DirectFeed feedR2 = directFeed(1); listR2.add(feedR2); // --- Checking SyncIn.Changes changes = SyncIn.evaluateChanges(local, remote, false); SyncIn.performChanges(local, changes, null); assertEquals(2, local.getGuidesCount()); IGuide guidea = local.getGuideAt(0); assertEquals("a", guidea.getTitle()); assertEquals(1, guidea.getFeedsCount()); DirectFeed feedA = (DirectFeed)guidea.getFeedAt(0); assertFalse("There should be no direct link.", guidea.hasDirectLinkWith(feedA)); assertEquals(feedR.getXmlURL().toString(), feedA.getXmlURL().toString()); ReadingList listA = feedA.getReadingLists()[0]; ReadingList[] listsA = ((StandardGuide)guidea).getReadingLists(); assertEquals(1, listsA.length); assertTrue(listA == listsA[0]); IGuide guideb = local.getGuideAt(1); assertEquals("b", guideb.getTitle()); assertEquals(1, guideb.getFeedsCount()); DirectFeed feedB = (DirectFeed)guideb.getFeedAt(0); assertFalse("There should be no direct link.", guideb.hasDirectLinkWith(feedB)); assertEquals(feedR2.getXmlURL().toString(), feedB.getXmlURL().toString()); ReadingList listB = feedB.getReadingLists()[1]; ReadingList[] listsB = ((StandardGuide)guideb).getReadingLists(); assertEquals(1, listsB.length); assertTrue(listB == listsB[0]); } /** * Reusing feeds for building other reading lists. */ public void testPerformChangesRLReuse() { // local StandardGuide guideL = guide("a"); local.add(guideL); ReadingList listL1 = readingList(1, true); guideL.add(listL1); DirectFeed feedL1 = directFeed(1); listL1.add(feedL1); ReadingList listL2 = readingList(2); guideL.add(listL2); DirectFeed feedL21 = directFeed(1); listL2.add(feedL21); DirectFeed feedL22 = directFeed(2); listL2.add(feedL22); // remote StandardGuide guideR = guide("a"); remote.add(guideR); ReadingList listR = readingList(3); guideR.add(listR); DirectFeed feedR = directFeed(1); listR.add(feedR); // --- Checking SyncIn.Changes changes = SyncIn.evaluateChanges(local, remote, false); SyncIn.performChanges(local, changes, null); assertEquals(1, local.getGuidesCount()); StandardGuide guide = (StandardGuide)local.getGuideAt(0); assertEquals(3, guide.getFeedsCount()); ReadingList[] lists = guide.getReadingLists(); assertEquals(2, lists.length); ReadingList list1 = lists[0]; assertEquals(listL2.getURL().toString(), list1.getURL().toString()); assertEquals(2, list1.getFeeds().length); ReadingList list2 = lists[1]; assertEquals(listR.getURL().toString(), list2.getURL().toString()); assertEquals(1, list2.getFeeds().length); } /** * An old guide with old feed is replaced with new guide and new feeds. */ public void testPerformChangesRLReplacing() { // local StandardGuide guideL = guide("a"); local.add(guideL); ReadingList listL1 = readingList(1, true); guideL.add(listL1); DirectFeed feedL1 = directFeed(1); listL1.add(feedL1); // remote StandardGuide guideR = guide("b"); remote.add(guideR); ReadingList listR = readingList(1); guideR.add(listR); DirectFeed feedR = directFeed(1); listR.add(feedR); guideR.add(directFeed(1)); // --- Checking SyncIn.Changes changes = SyncIn.evaluateChanges(local, remote, false); SyncIn.performChanges(local, changes, null); assertEquals(1, local.getGuidesCount()); StandardGuide guide = (StandardGuide)local.getGuideAt(0); assertEquals(1, guide.getFeedsCount()); ReadingList[] lists = guide.getReadingLists(); assertEquals(1, lists.length); ReadingList list1 = lists[0]; assertEquals(1, list1.getFeeds().length); } /** * User added new guide "a" and reading list "1" with one feed "1". Next, he loads * his guide "b" with readig list "1", feed "1" and static feed "1". All feeds and guides * should be combined. */ public void testPerformChangesRLAdding() { // local StandardGuide guideL = guide("a"); local.add(guideL); ReadingList listL1 = readingList(1); guideL.add(listL1); DirectFeed feedL1 = directFeed(1); listL1.add(feedL1); // remote StandardGuide guideR = guide("b"); remote.add(guideR); ReadingList listR = readingList(1); guideR.add(listR); DirectFeed feedR = directFeed(1); listR.add(feedR); guideR.add(directFeed(1)); // --- Checking SyncIn.Changes changes = SyncIn.evaluateChanges(local, remote, false); SyncIn.performChanges(local, changes, null); assertEquals(2, local.getGuidesCount()); StandardGuide guide = (StandardGuide)local.getGuideAt(0); assertEquals(1, guide.getFeedsCount()); ReadingList[] lists = guide.getReadingLists(); assertEquals(1, lists.length); ReadingList list1 = lists[0]; assertEquals(1, list1.getFeeds().length); StandardGuide guide2 = (StandardGuide)local.getGuideAt(1); assertEquals(1, guide2.getFeedsCount()); ReadingList[] lists2 = guide2.getReadingLists(); assertEquals(1, lists2.length); ReadingList list12 = lists2[0]; assertEquals(1, list12.getFeeds().length); } /** * Tests converting reading list feed to normal. */ public void testPerformChangesRLFeedConversion() { // local StandardGuide guideL = guide("a"); local.add(guideL); ReadingList listL1 = readingList(1, true); guideL.add(listL1); DirectFeed feedL1 = directFeed(1); listL1.add(feedL1); // remote StandardGuide guideR = guide("a"); remote.add(guideR); DirectFeed feedR = directFeed(1); guideR.add(feedR); // --- Checking SyncIn.Changes changes = SyncIn.evaluateChanges(local, remote, false); SyncIn.performChanges(local, changes, null); assertEquals(1, local.getGuidesCount()); StandardGuide guide = (StandardGuide)local.getGuideAt(0); assertEquals(1, guide.getFeedsCount()); ReadingList[] lists = guide.getReadingLists(); assertEquals(0, lists.length); DirectFeed feed = (DirectFeed)guide.getFeedAt(0); assertEquals("There should be no connection to reading list.", 0, feed.getReadingLists().length); } // Read state sync ----------------------------------------------------------------------------- /** * Local feed has 2 articles with one of them read. Remotely user read both of articles * and he synchronizes the state back from service. Both articles should be marked as read. */ public void testReadState() { // Local StandardGuide guideL = guide("a"); local.add(guideL); DirectFeed feedL = directFeed(1); addAndMarkAsSynced(guideL, feedL); StandardArticle artL1 = new StandardArticle("a"); feedL.appendArticle(artL1); StandardArticle artL2 = new StandardArticle("b"); feedL.appendArticle(artL2); feedL.setInitTime(1L); artL1.setRead(true); // Create illusion that remotely we have both articles read artL2.setRead(true); String remoteKeys = feedL.getReadArticlesKeys(); artL2.setRead(false); // Remote StandardGuide guideR = guide("a"); remote.add(guideR); DirectFeed feedR = directFeed(1); addAndMarkAsSynced(guideR, feedR); feedR.setReadArticlesKeys(remoteKeys); assertEquals(remoteKeys, feedR.getReadArticlesKeys()); // --- Checking SyncIn.Changes changes = SyncIn.evaluateChanges(local, remote, false); assertEquals(1, changes.getUpdateFeedsKeys().size()); SyncIn.performChanges(local, changes, null); assertEquals(0, feedL.getUnreadArticlesCount()); } // Pin state sync ------------------------------------------------------------------------------ /** * Local feed has 2 articles with one of them pinned. Remotely user pinned both of articles * and he synchronizes the state back from service. Both articles should be marked as pinned. */ public void testPinnedState() { // Local StandardGuide guideL = guide("a"); local.add(guideL); DirectFeed feedL = directFeed(1); addAndMarkAsSynced(guideL, feedL); StandardArticle artL1 = new StandardArticle("a"); feedL.appendArticle(artL1); StandardArticle artL2 = new StandardArticle("b"); feedL.appendArticle(artL2); feedL.setInitTime(1L); artL1.setPinned(true); // Create illusion that remotely we have both articles read artL2.setPinned(true); String remoteKeys = feedL.getPinnedArticlesKeys(); artL2.setPinned(false); // Remote StandardGuide guideR = guide("a"); remote.add(guideR); DirectFeed feedR = directFeed(1); addAndMarkAsSynced(guideR, feedR); feedR.setPinnedArticlesKeys(remoteKeys); assertEquals(remoteKeys, feedR.getPinnedArticlesKeys()); // --- Checking SyncIn.Changes changes = SyncIn.evaluateChanges(local, remote, false); assertEquals(1, changes.getUpdateFeedsKeys().size()); SyncIn.performChanges(local, changes, null); IArticle[] articles = feedL.getArticles(); int pinned = 0; for (int i = 0; i < articles.length; i++) if (articles[i].isPinned()) pinned++; assertEquals(1, pinned); } // View type / mode sync ----------------------------------------------------------------------- public void testViewTypeModeSyncDirect() { // Local StandardGuide guideL = guide("a"); local.add(guideL); DirectFeed feedL = directFeed(1); addAndMarkAsSynced(guideL, feedL); feedL.setInitTime(1L); feedL.setCustomViewModeEnabled(false); feedL.setCustomViewMode(1); feedL.setType(FeedType.IMAGE); // Remote StandardGuide guideR = guide("a"); remote.add(guideR); DirectFeed feedR = directFeed(1); addAndMarkAsSynced(guideR, feedR); feedR.setCustomViewModeEnabled(true); feedR.setCustomViewMode(0); feedR.setType(FeedType.TEXT); // Update // Rewind update time a bit so that the remote version is newer feedL.setLastUpdateTime(System.currentTimeMillis() - 1000); SyncIn.Changes changes = SyncIn.evaluateChanges(local, remote, false); assertEquals(1, changes.getUpdateFeedsKeys().size()); SyncIn.performChanges(local, changes, null); // Check assertEquals(0, feedL.getCustomViewMode()); assertTrue(feedL.isCustomViewModeEnabled()); assertEquals(FeedType.TEXT, feedL.getType()); } // Hashes -------------------------------------------------------------------------------------- /** * Checking the feeds matching using the saved sync hash. */ public void testFeedsAreTheSame_Direct() { // No hash DirectFeed d1 = directFeed(1); DirectFeed d2 = directFeed(1); assertTrue(SyncIn.feedsAreTheSameDirect(d1, d2)); // Wrong URL but hash d2 = directFeed(2); d2.setSyncHash(d1.calcSyncHash()); assertTrue(SyncIn.feedsAreTheSameDirect(d1, d2)); // Wrong URL, wrong hash d2 = directFeed(2); assertFalse(SyncIn.feedsAreTheSameDirect(d1, d2)); } // Utilities ----------------------------------------------------------------------------------- /** * Creates a reading list with URL having identifier specified. * * @param n identifier. * * @return reading list. */ private ReadingList readingList(int n) { return readingList(n, false); } /** * Creates a reading list with URL having identifier specified. * * @param n identifier. * @param synced <code>TRUE</code> to mark as synchronized. * * @return reading list. */ private ReadingList readingList(int n, boolean synced) { ReadingList list = new ReadingList(getURL(n)); if (synced) list.setLastSyncTime(1L); return list; } /** * Creates a guide with the given title. * * @param name title. * * @return guide. */ private StandardGuide guide(String name) { StandardGuide guide = new StandardGuide(); guide.setTitle(name); return guide; } /** * Creates a search feed with a title and query both having an identifier. * * @param n identifier. * * @return search feed. */ private SearchFeed searchFeed(int n) { Query query = new Query(); ICriteria criteria = query.addCriteria(); criteria.setProperty(ArticleTextProperty.INSTANCE); criteria.setComparisonOperation(StringEqualsCO.INSTANCE); criteria.setValue(Integer.toString(n)); SearchFeed feed = new SearchFeed(); feed.setBaseTitle(Integer.toString(n)); feed.setQuery(query); return feed; } /** * Creates a query feed with a title and query both having an identifier. * * @param n identifier. * * @return query feed. */ private QueryFeed queryFeed(int n) { QueryFeed feed = new QueryFeed(); feed.setBaseTitle(Integer.toString(n)); feed.setQueryType(QueryType.getQueryType(QueryType.TYPE_AMAZON_BOOKS)); feed.setParameter("test"); return feed; } /** * Creates a direct feed with a name and URL both including the identifier. * * @param n identifier. * * @return direct feed. */ private DirectFeed directFeed(int n) { DirectFeed feed = new DirectFeed(); feed.setBaseTitle(Integer.toString(n)); feed.setXmlURL(getURL(n)); return feed; } /** * Adds the feed to the guide and marks it as synchronized. * * @param guide guide. * @param feed feed. */ private void addAndMarkAsSynced(StandardGuide guide, IFeed feed) { guide.add(feed); guide.getFeedLinkInfo(feed).setLastSyncTime(1L); } /** * Returns some test URL. * * @param n identifier to put inside the URL. * * @return test URL. */ private URL getURL(int n) { URL url = null; try { url = new URL("file://" + n); } catch (MalformedURLException e) { fail(); } return url; } }