Package com.salas.bb.service.sync

Source Code of com.salas.bb.service.sync.TestSyncIn

// 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;
    }
}
TOP

Related Classes of com.salas.bb.service.sync.TestSyncIn

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.