// BlogBridge -- RSS feed reader, manager, and web based service
// Copyright (C) 2002-2007 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: TestListModelEvents.java,v 1.6 2008/02/28 15:59:52 spyromus Exp $
//
package com.salas.bb.whatshot;
import com.jgoodies.binding.value.ValueHolder;
import com.jgoodies.uif.util.ResourceUtils;
import com.salas.bb.domain.*;
import com.salas.bb.search.IResultsListModelListener;
import com.salas.bb.search.ResultGroup;
import com.salas.bb.search.ResultItem;
import org.jmock.Mock;
import org.jmock.MockObjectTestCase;
import org.jmock.builder.MatchBuilder;
import org.jmock.core.constraint.IsEqual;
import java.util.Date;
import java.util.List;
/**
* Tests the events fired by the {@link ListModel}.
*/
public class TestListModelEvents extends MockObjectTestCase
{
/** Mock listener. */
private Mock listener;
/** Model to operate. */
private ListModel model;
private StandardArticle article11;
private StandardArticle article12;
private StandardArticle article13;
private StandardArticle article21;
private StandardArticle article22;
private StandardArticle article31;
private DirectFeed feed1;
private DirectFeed feed2;
private DirectFeed feed3;
private StandardGuide guide1;
private StandardGuide guide2;
private GuidesSet set;
private int seq;
private Engine engine;
private ValueHolder mdlStarz;
private ValueHolder mdlOnlyUnread;
private ValueHolder mdlToday;
/**
* Configures the environment.
*
* @throws Exception if something goes wrong.
*/
protected void setUp() throws Exception
{
super.setUp();
listener = new Mock(IResultsListModelListener.class);
seq = 0;
ResourceUtils.setBundlePath("Resource");
// Create 6 articles: 3 for the first feed, 2 for the second and 1 for the third
article11 = article(mention("1", "1"), "11");
article12 = article(mention("1", "2"), "12");
article13 = article(mention("1", "3"), "13");
article21 = article(mention("2", "1"), "21");
article22 = article(mention("2", "2"), "22");
article31 = article(mention("3", "1"), "31");
// Create 3 feeds
feed1 = new DirectFeed();
feed1.appendArticle(article11);
feed1.appendArticle(article12);
feed1.appendArticle(article13);
feed2 = new DirectFeed();
feed2.appendArticle(article21);
feed2.appendArticle(article22);
feed3 = new DirectFeed();
feed3.appendArticle(article31);
// Create 2 guides
guide1 = new StandardGuide();
guide1.setTitle("1");
guide1.add(feed1);
guide1.add(feed2);
guide2 = new StandardGuide();
guide2.setTitle("2");
guide1.add(feed3);
// Create the guides set
set = new GuidesSet();
set.add(guide1);
set.add(guide2);
// Create a model with an item
engine = new Engine(set);
mdlStarz = new ValueHolder(1);
mdlOnlyUnread = new ValueHolder(false);
mdlToday = new ValueHolder(TimeOption.THIS_WEEK);
model = new ListModel(engine, mdlStarz, mdlOnlyUnread, mdlToday);
model.addListener((IResultsListModelListener)listener.proxy());
}
private StandardArticle article(String text, String title)
{
StandardArticle article = new StandardArticle(text);
article.setTitle(title);
article.setPublicationDate(new Date());
return article;
}
/**
* Tests initial scanning of the set.
*/
public void testInitialScan()
{
// Current model configuration is: 1 star, all guides, read/unread
expectOnClear();
expectOnGroupAdded("1");
expectOnItemAdded(article11, "1");
expectOnItemAdded(article12, "1");
expectOnItemAdded(article13, "1");
expectOnItemAdded(article21, "1");
expectOnItemAdded(article31, "1");
expectOnGroupAdded("2");
expectOnItemAdded(article12, "2");
expectOnItemAdded(article21, "2");
expectOnItemAdded(article22, "2");
expectOnGroupAdded("3");
expectOnItemAdded(article13, "3");
expectOnItemAdded(article31, "3");
scan();
listener.verify();
}
/**
* Tests hiding read items and empty groups.
*/
public void testSwitchingUnreadOnly()
{
// Set the following articles as read: 12, 22, 13
// This will:
// 1) remove 2 articles from the first set
// 2) remove 2 articles from the second set and hide it
// 3) remove 1 article from the third set and hide it
article12.setRead(true);
article22.setRead(true);
article13.setRead(true);
// Skip any events
listener.expects(atLeastOnce()).method(ANYTHING);
// Current model configuration is: 1 star, all guides, read/unread
scan();
// Configure expectations
expectOnClear();
expectOnGroupAdded("1");
expectOnItemAdded(article11, "1");
expectOnItemAdded(article21, "1");
expectOnItemAdded(article31, "1");
// Change mode to unread only
mdlOnlyUnread.setValue(true);
listener.verify();
}
/**
* Tests showing read items and empty groups.
*/
public void testSwitchingNotUnreadOnly()
{
// Set the following articles as read: 12, 22, 13
// This will:
// 1) remove 2 articles from the first set
// 2) remove 2 articles from the second set and hide it
// 3) remove 1 article from the third set and hide it
article12.setRead(true);
article22.setRead(true);
article13.setRead(true);
// Skip any events
listener.expects(atLeastOnce()).method(ANYTHING);
// Current model configuration is: 1 star, all guides, read/unread
scan();
mdlOnlyUnread.setValue(true);
// Configure expectations
expectOnClear();
expectOnGroupAdded("1");
expectOnItemAdded(article11, "1");
expectOnItemAdded(article12, "1");
expectOnItemAdded(article13, "1");
expectOnItemAdded(article21, "1");
expectOnItemAdded(article31, "1");
expectOnGroupAdded("2");
expectOnItemAdded(article12, "2");
expectOnItemAdded(article21, "2");
expectOnItemAdded(article22, "2");
expectOnGroupAdded("3");
expectOnItemAdded(article13, "3");
expectOnItemAdded(article31, "3");
// Switch non-unread only mode on
mdlOnlyUnread.setValue(false);
listener.verify();
}
/**
* Single-threaded equivalent of {@link com.salas.bb.whatshot.ListModel#scan()}.
*/
private void scan()
{
List<Engine.HotLink> links = engine.scan();
model.processLinks(links);
}
/**
* Returns the HTML text mentioning the links given.
*
* @param links links.
*
* @return HTML.
*/
private String mention(String ... links)
{
String text = "";
for (String link : links)
{
text += "<a href=\"http://" + link + ".com\">link</a>";
}
return text;
}
private void expectOnClear()
{
MatchBuilder b = listener.expects(once()).method("onClear").with(same(model));
setupIdAfter(b);
}
private void expectOnGroupAdded(String groupName)
{
MatchBuilder b = listener.expects(once()).method("onGroupAdded").with(
same(model), groupEq("http://" + groupName + ".com"), eq(true));
setupIdAfter(b);
}
private void expectOnGroupUpdated(String groupName)
{
MatchBuilder b = listener.expects(once()).method("onGroupUpdated").with(
same(model), groupEq("http://" + groupName + ".com"));
setupIdAfter(b);
}
private void expectOnGroupRemoved(String groupName)
{
MatchBuilder b = listener.expects(once()).method("onGroupRemoved").with(
same(model), groupEq("http://" + groupName + ".com"));
setupIdAfter(b);
}
private void expectOnItemAdded(IArticle article, String groupName)
{
MatchBuilder b = listener.expects(once()).method("onItemAdded").with(
same(model), itemEq(article), groupEq("http://" + groupName + ".com"));
setupIdAfter(b);
}
private void expectOnItemRemoved(IArticle article, String groupName)
{
MatchBuilder b = listener.expects(once()).method("onItemRemoved").with(
same(model), itemEq(article), groupEq("http://" + groupName + ".com"));
setupIdAfter(b);
}
private void setupIdAfter(MatchBuilder b)
{
if (seq > 0) b.after(Integer.toString(seq - 1));
b.id(Integer.toString(seq++));
}
private GroupEq groupEq(String link)
{
return new GroupEq(link);
}
private ItemEq itemEq(IArticle article)
{
return new ItemEq(article);
}
private static class GroupEq extends IsEqual
{
private final String link;
public GroupEq(String link)
{
super(link);
this.link = link;
}
@Override
public boolean eval(Object o)
{
if (!(o instanceof ResultGroup)) return false;
ResultGroup g = (ResultGroup)o;
return g.getName().equals(link);
}
@Override
public StringBuffer describeTo(StringBuffer stringBuffer)
{
return stringBuffer.append("groupEq(<").append(link).append(">)");
}
}
private static class ItemEq extends IsEqual
{
private final IArticle article;
public ItemEq(IArticle article)
{
super(article);
this.article = article;
}
@Override
public boolean eval(Object o)
{
if (!(o instanceof ResultItem)) return false;
ResultItem i = (ResultItem)o;
return i.getObject() == article;
}
@Override
public StringBuffer describeTo(StringBuffer stringBuffer)
{
return stringBuffer.append("itemEq(<").append(article.getTitle()).append(">)");
}
}
}