// 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: TestGuideModel.java,v 1.11 2008/02/28 15:59:50 spyromus Exp $ // package com.salas.bb.core; import com.salas.bb.domain.*; import junit.framework.TestCase; /** * This suite contains tests for <code>GuideModel</code> unit. * It covers: * <ul> * <li>Check for bug with moving feeds.</li> * </ul> */ public class TestGuideModel extends TestCase { /** * <p>Tests the behaviour with removing and adding feeds in a sequence. The bug appeared * when doing D'n'D within the same guide. The feed has beed removed and then added * back resulting in IOOBE. The bug only appeared when sorting was off.</p> * * <p>The problem was in <code>copyFeedsList()</code> method's <code>!sort</code> branch * where the destination array has been created with the size being out of sync with * filtered array.</p> */ public void testAddRemoveFeed() { ScoresCalculator calc = new ScoresCalculator(); FeedDisplayModeManager feedDMM = new FeedDisplayModeManager() { public synchronized boolean isVisible(int channelClass) { return true; } }; // Create and select some guide GuideModel model = new GuideModel(calc, false, feedDMM); model.setSortingEnabled(false); StandardGuide guide = new StandardGuide(); model.setGuide(guide); // Add two feeds to the guide and notify model DirectFeed feed0 = new DirectFeed(); guide.add(feed0); model.feedsAdded(0, 0); DirectFeed feed1 = new DirectFeed(); guide.add(feed1); model.feedsAdded(1, 1); // Remove the last feed and add it back on the first place guide.remove(feed1); model.fullRebuild(); guide.add(feed1); model.feedsAdded(1, 1); } /** * Tests shifting in invalidness bit. */ public void testShiftInSortMaskInvalidness() { checkShift(FeedClass.INVALID, FeedsSortOrder.INVALIDNESS); } /** * Tests shifting in rating bit. */ public void testShiftInSortMaskRating() { CustomScoreCalculationsModel model = new CustomScoreCalculationsModel(); DirectFeed feed = new DirectFeed(); int minVisits = 0; int score = model.shiftInSortMark(1, 0, feed, FeedsSortOrder.RATING, false, minVisits); assertEquals((1 << 3) | 7, score); feed.setRating(4); score = model.shiftInSortMark(1, 0, feed, FeedsSortOrder.RATING, true, minVisits); assertEquals((1 << 3) | 4, score); } /** * Tests shifting in readness bit. */ public void testShiftInSortMaskRead() { checkShift(FeedClass.READ, FeedsSortOrder.READ); } /** * Tests shifting in undiscoveredness bit. */ public void testShiftInSortMaskUndiscovered() { checkShift(FeedClass.UNDISCOVERED, FeedsSortOrder.INVALIDNESS); } /** * Tests shifting in alphabetical order. */ public void testShiftInSortMaskAlphabetical() { DirectFeed feed = new DirectFeed(); // We put the alpha order of this feed in ID to emulate the reporting // of its actual position by parent guide (which is missing in this test) feed.setID(1023); int score; CustomScoreCalculationsModel model = new CustomScoreCalculationsModel(); int minVisits = 0; score = model.shiftInSortMark(1, 0, feed, FeedsSortOrder.ALPHABETICAL, false, minVisits); assertEquals((1 << 10) | 1023, score); score = model.shiftInSortMark(1, 0, feed, FeedsSortOrder.ALPHABETICAL, true, minVisits); assertEquals((1 << 10) | 0, score); } /** * Tests calculation of complex score. */ public void testCalculateScore() { DirectFeed feed = new DirectFeed(); // We put the alpha order of this feed in ID to emulate the reporting // of its actual position by parent guide (which is missing in this test) feed.setID(1023); feed.setRating(3); feed.setRead(false); int targetScore; int feedClass; int score; CustomScoreCalculationsModel model = new CustomScoreCalculationsModel(); model.setPrimarySortOrder(FeedsSortOrder.ALPHABETICAL); model.setSecondarySortOrder(FeedsSortOrder.RATING); feedClass = FeedClass.LOW_RATED; // 10bits-alphaOrder : 3bit-lowHighRating : 3bit-ratingValue // 1023 : 1 (low rated) : 1 (4-3 for more starz to go first) targetScore = ((((1023 << 3) | 4) << 3) | 1); score = model.calculateScore(feed, feedClass, 0); assertEquals("Wrong calculation of score.", targetScore, score); // Sort by visits (less to more) and read flag (read on top) // Ratings and alpha sorting should be automatically added model.setPrimarySortOrder(FeedsSortOrder.VISITS); model.setPrimarySortOrderDirection(true); model.setSecondarySortOrder(FeedsSortOrder.READ); feedClass = 0; // Read Flag (1 bit) : Rating (3 bit) : Alpha Order (10 bit) // 0 (unread) : 1 (4-3) : 1023 targetScore = (((0 << 3) | 1) << 10) | 1023; score = model.calculateScore(feed, feedClass, 0); assertEquals("Wrong calculation of score.", targetScore, score); } /** Tests handling simple situations without NPE. */ public void testEnsureVisibilityOf() { GuideModel model = new GuideModel(null, false, null); model.ensureVisibilityOf(new DirectFeed()); model.ensureVisibilityOf(null); } /** Verifies that the given combination of feedClass and sortOrder produces right bit shift. */ private void checkShift(int feedClass, int sortOrder) { int score; CustomScoreCalculationsModel model = new CustomScoreCalculationsModel(); DirectFeed feed = new DirectFeed(); int minVisits = 0; score = model.shiftInSortMark(1, 0, feed, sortOrder, false, minVisits); assertEquals((1 << 1) | 0, score); score = model.shiftInSortMark(1, feedClass, feed, sortOrder, false, minVisits); assertEquals((1 << 1) | 1, score); score = model.shiftInSortMark(1, feedClass, feed, sortOrder, true, minVisits); assertEquals((1 << 1) | 0, score); } /** * Model which overriden calls to calculators. Feed keywords count is static. * Feed rating is always taken from feed setting. Feed alpha order is taken from * <code>ID</code> field (yes, it's hack for exactly this implementation to * avoid calling external modules). */ private static class CustomScoreCalculationsModel extends GuideModel { private int feedKeywords; /** Constructs the model. */ public CustomScoreCalculationsModel() { super(null, null); } /** * Returns rating of the feed for further math. * * @param feed feed. * * @return rating in range [0;4]. */ int getFeedRating(IFeed feed) { return feed.getRating(); } /** * Returns alphabetical order index of the feed within the currently selected guide. * * @param feed feed. * * @return order index in range [0;1023]. */ int getFeedAlphaOrder(IFeed feed) { return (int)feed.getID(); } } }