/* ********************************************************************** **
** Copyright notice **
** **
** (c) 2005-2009 RSSOwl Development Team **
** http://www.rssowl.org/ **
** **
** All rights reserved **
** **
** This program and the accompanying materials are made available under **
** the terms of the Eclipse Public License v1.0 which accompanies this **
** distribution, and is available at: **
** http://www.rssowl.org/legal/epl-v10.html **
** **
** A copy is found in the file epl-v10.html and important notices to the **
** license from the team is found in the textfile LICENSE.txt distributed **
** in this package. **
** **
** This copyright notice MUST APPEAR in all copies of the file! **
** **
** Contributors: **
** RSSOwl Development Team - initial API and implementation **
** **
** ********************************************************************** */
package org.rssowl.core.tests.ui;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
import org.junit.Before;
import org.junit.Test;
import org.rssowl.core.Owl;
import org.rssowl.core.internal.persist.service.PersistenceServiceImpl;
import org.rssowl.core.persist.IBookMark;
import org.rssowl.core.persist.IFeed;
import org.rssowl.core.persist.IFolder;
import org.rssowl.core.persist.IModelFactory;
import org.rssowl.core.persist.INews;
import org.rssowl.core.persist.INewsBin;
import org.rssowl.core.persist.dao.DynamicDAO;
import org.rssowl.core.persist.dao.INewsDAO;
import org.rssowl.core.persist.reference.FeedLinkReference;
import org.rssowl.ui.internal.undo.CopyOperation;
import org.rssowl.ui.internal.undo.MoveOperation;
import org.rssowl.ui.internal.undo.NewsStateOperation;
import org.rssowl.ui.internal.undo.StickyOperation;
import org.rssowl.ui.internal.undo.UndoStack;
import java.net.URI;
import java.util.Collections;
import java.util.Date;
/**
* Tests for the {@link UndoStack}.
*
* @author bpasero
*/
public class UndoTest {
private IModelFactory fFactory;
/**
* @throws Exception
*/
@Before
public void setUp() throws Exception {
fFactory = Owl.getModelFactory();
((PersistenceServiceImpl)Owl.getPersistenceService()).recreateSchemaForTests();
UndoStack.getInstance().clear();
}
/**
* @throws Exception
*/
@Test
public void testUndoCopy() throws Exception {
IFeed feed = fFactory.createFeed(null, new URI("http://www.foo1.com"));
INews news = fFactory.createNews(null, feed, new Date());
news.setLink(new URI("http://www.news.com"));
DynamicDAO.save(feed);
IFolder folder = fFactory.createFolder(null, null, "Root");
INewsBin bin = fFactory.createNewsBin(null, folder, "Bin");
DynamicDAO.save(folder);
INews copiedNews = fFactory.createNews(news, bin);
DynamicDAO.save(copiedNews);
DynamicDAO.save(bin);
UndoStack.getInstance().addOperation(new CopyOperation(Collections.singletonList(copiedNews)));
assertTrue(bin.containsNews(copiedNews));
UndoStack.getInstance().undo();
assertEquals(0, bin.getNewsCount(INews.State.getVisible()));
UndoStack.getInstance().redo();
assertTrue(bin.containsNews(copiedNews));
}
/**
* @throws Exception
*/
@Test
public void testUndoMove() throws Exception {
IFeed feed = fFactory.createFeed(null, new URI("http://www.foo1.com"));
INews news = fFactory.createNews(null, feed, new Date());
news.setLink(new URI("http://www.news.com"));
DynamicDAO.save(feed);
IFolder folder = fFactory.createFolder(null, null, "Root");
IBookMark bookmark = fFactory.createBookMark(null, folder, new FeedLinkReference(feed.getLink()), "Bookmark");
INewsBin bin = fFactory.createNewsBin(null, folder, "Bin");
DynamicDAO.save(folder);
INews copiedNews = fFactory.createNews(news, bin);
DynamicDAO.save(copiedNews);
DynamicDAO.save(bin);
UndoStack.getInstance().addOperation(new MoveOperation(Collections.singletonList(news), Collections.singletonList(copiedNews), false));
/* Remove (it's a move!) */
DynamicDAO.getDAO(INewsDAO.class).setState(Collections.singletonList(news), INews.State.HIDDEN, false, false);
assertTrue(bin.containsNews(copiedNews));
assertTrue(bookmark.getNewsCount(INews.State.getVisible()) == 0);
UndoStack.getInstance().undo();
assertTrue(bin.getNewsCount(INews.State.getVisible()) == 0);
assertTrue(bookmark.containsNews(news));
assertTrue(bookmark.getNewsCount(INews.State.getVisible()) > 0);
UndoStack.getInstance().redo();
assertTrue(bin.containsNews(copiedNews));
assertTrue(bookmark.getNewsCount(INews.State.getVisible()) == 0);
}
/**
* @throws Exception
*/
@Test
public void testUndoStateChange() throws Exception {
IFeed feed = fFactory.createFeed(null, new URI("http://www.foo1.com"));
INews news = fFactory.createNews(null, feed, new Date());
news.setLink(new URI("http://www.news.com"));
DynamicDAO.save(feed);
UndoStack.getInstance().addOperation(new NewsStateOperation(Collections.singletonList(news), INews.State.READ, false));
DynamicDAO.getDAO(INewsDAO.class).setState(Collections.singletonList(news), INews.State.READ, false, false);
assertEquals(INews.State.READ, news.getState());
UndoStack.getInstance().undo();
assertEquals(INews.State.NEW, news.getState());
UndoStack.getInstance().redo();
assertEquals(INews.State.READ, news.getState());
UndoStack.getInstance().addOperation(new NewsStateOperation(Collections.singletonList(news), INews.State.HIDDEN, false));
DynamicDAO.getDAO(INewsDAO.class).setState(Collections.singletonList(news), INews.State.HIDDEN, false, false);
assertEquals(INews.State.HIDDEN, news.getState());
UndoStack.getInstance().undo();
assertEquals(INews.State.READ, news.getState());
UndoStack.getInstance().redo();
assertEquals(INews.State.HIDDEN, news.getState());
}
/**
* @throws Exception
*/
@Test
public void testUndoStateChangeAffectEquivalent() throws Exception {
IFeed feed1 = fFactory.createFeed(null, new URI("http://www.foo1.com"));
INews news1 = fFactory.createNews(null, feed1, new Date());
news1.setLink(new URI("http://www.news.com"));
IFeed feed2 = fFactory.createFeed(null, new URI("http://www.foo2.com"));
INews news2 = fFactory.createNews(null, feed2, new Date());
news2.setLink(new URI("http://www.news.com"));
DynamicDAO.save(feed1);
DynamicDAO.save(feed2);
UndoStack.getInstance().addOperation(new NewsStateOperation(Collections.singletonList(news1), INews.State.READ, true));
DynamicDAO.getDAO(INewsDAO.class).setState(Collections.singletonList(news1), INews.State.READ, true, false);
assertEquals(INews.State.READ, news1.getState());
assertEquals(INews.State.READ, news2.getState());
UndoStack.getInstance().undo();
assertEquals(INews.State.NEW, news1.getState());
assertEquals(INews.State.NEW, news2.getState());
UndoStack.getInstance().redo();
assertEquals(INews.State.READ, news1.getState());
assertEquals(INews.State.READ, news2.getState());
}
/**
* @throws Exception
*/
@Test
public void testUndoSticky() throws Exception {
IFeed feed = fFactory.createFeed(null, new URI("http://www.foo1.com"));
INews news = fFactory.createNews(null, feed, new Date());
news.setLink(new URI("http://www.news.com"));
DynamicDAO.save(feed);
UndoStack.getInstance().addOperation(new StickyOperation(Collections.singletonList(news), true));
news.setFlagged(true);
DynamicDAO.save(news);
UndoStack.getInstance().undo();
assertEquals(false, news.isFlagged());
UndoStack.getInstance().redo();
assertEquals(true, news.isFlagged());
}
/**
* @throws Exception
*/
@Test
public void testUndoDeleteAndSticky() throws Exception {
IFolder root = fFactory.createFolder(null, null, "Root");
IFeed feed = fFactory.createFeed(null, new URI("http://www.foo1.com"));
INews news = fFactory.createNews(null, feed, new Date());
news.setLink(new URI("http://www.news.com"));
news.setFlagged(true);
DynamicDAO.save(feed);
IBookMark bookmark = fFactory.createBookMark(null, root, new FeedLinkReference(feed.getLink()), "Bookmark");
DynamicDAO.save(root);
assertEquals(1, bookmark.getStickyNewsCount());
assertEquals(1, bookmark.getNewsCount(INews.State.getVisible()));
UndoStack.getInstance().addOperation(new NewsStateOperation(Collections.singleton(news), INews.State.HIDDEN, false));
DynamicDAO.getDAO(INewsDAO.class).setState(Collections.singleton(news), INews.State.HIDDEN, false, false);
assertEquals(0, bookmark.getStickyNewsCount());
assertEquals(0, bookmark.getNewsCount(INews.State.getVisible()));
UndoStack.getInstance().undo();
assertEquals(1, bookmark.getStickyNewsCount());
assertEquals(1, bookmark.getNewsCount(INews.State.getVisible()));
UndoStack.getInstance().redo();
assertEquals(0, bookmark.getStickyNewsCount());
assertEquals(0, bookmark.getNewsCount(INews.State.getVisible()));
}
/**
* @throws Exception
*/
@Test
public void testNewActionFromUndoActionDeletesAllFollowingRedoActions() throws Exception {
IFeed feed = fFactory.createFeed(null, new URI("http://www.foo1.com"));
INews news = fFactory.createNews(null, feed, new Date());
news.setLink(new URI("http://www.news.com"));
DynamicDAO.save(feed);
UndoStack.getInstance().addOperation(new StickyOperation(Collections.singletonList(news), true));
news.setFlagged(true);
DynamicDAO.save(news);
UndoStack.getInstance().undo();
assertEquals(false, news.isFlagged());
assertEquals(true, UndoStack.getInstance().isRedoSupported());
UndoStack.getInstance().addOperation(new StickyOperation(Collections.singletonList(news), true));
assertEquals(false, UndoStack.getInstance().isRedoSupported());
}
/**
* @throws Exception
*/
@Test
public void testUndoRedoNewsState() throws Exception {
IFeed feed = fFactory.createFeed(null, new URI("http://www.foo1.com"));
INews news = fFactory.createNews(null, feed, new Date());
news.setLink(new URI("http://www.news.com"));
news.setState(INews.State.READ);
DynamicDAO.save(feed);
UndoStack.getInstance().addOperation(new NewsStateOperation(Collections.singletonList(news), INews.State.UNREAD, false));
DynamicDAO.getDAO(INewsDAO.class).setState(Collections.singletonList(news), INews.State.UNREAD, false, false);
assertEquals(INews.State.UNREAD, news.getState());
UndoStack.getInstance().addOperation(new NewsStateOperation(Collections.singletonList(news), INews.State.READ, false));
DynamicDAO.getDAO(INewsDAO.class).setState(Collections.singletonList(news), INews.State.READ, false, false);
assertEquals(INews.State.READ, news.getState());
UndoStack.getInstance().undo();
UndoStack.getInstance().undo();
assertEquals(INews.State.READ, news.getState());
UndoStack.getInstance().addOperation(new NewsStateOperation(Collections.singletonList(news), INews.State.UNREAD, false));
DynamicDAO.getDAO(INewsDAO.class).setState(Collections.singletonList(news), INews.State.UNREAD, false, false);
assertEquals(INews.State.UNREAD, news.getState());
UndoStack.getInstance().addOperation(new NewsStateOperation(Collections.singletonList(news), INews.State.READ, false));
DynamicDAO.getDAO(INewsDAO.class).setState(Collections.singletonList(news), INews.State.READ, false, false);
assertEquals(INews.State.READ, news.getState());
UndoStack.getInstance().undo();
UndoStack.getInstance().undo();
assertEquals(INews.State.READ, news.getState());
assertEquals(false, UndoStack.getInstance().isUndoSupported());
}
/**
* @throws Exception
*/
@Test
public void testUndoRedoExceedsMaxLimit() throws Exception {
IFeed feed = fFactory.createFeed(null, new URI("http://www.foo1.com"));
INews news = fFactory.createNews(null, feed, new Date());
news.setLink(new URI("http://www.news.com"));
news.setState(INews.State.READ);
DynamicDAO.save(feed);
UndoStack.getInstance().addOperation(new StickyOperation(Collections.singletonList(news), true));
news.setFlagged(true);
DynamicDAO.save(news);
for (int i = 0; i < 20; i++) {
UndoStack.getInstance().addOperation(new NewsStateOperation(Collections.singletonList(news), i % 2 == 0 ? INews.State.UNREAD : INews.State.READ, false));
DynamicDAO.getDAO(INewsDAO.class).setState(Collections.singletonList(news), i % 2 == 0 ? INews.State.UNREAD : INews.State.READ, false, false);
}
int undos = 0;
while (UndoStack.getInstance().isUndoSupported()) {
UndoStack.getInstance().undo();
undos++;
}
assertEquals(true, news.toReference().resolve().isFlagged());
assertEquals(20, undos);
assertEquals(true, UndoStack.getInstance().isRedoSupported());
int redos = 0;
while (UndoStack.getInstance().isRedoSupported()) {
UndoStack.getInstance().redo();
redos++;
}
assertEquals(20, redos);
while (UndoStack.getInstance().isUndoSupported()) {
UndoStack.getInstance().undo();
}
UndoStack.getInstance().addOperation(new StickyOperation(Collections.singletonList(news), false));
news.setFlagged(false);
DynamicDAO.save(news);
undos = 0;
while (UndoStack.getInstance().isUndoSupported()) {
UndoStack.getInstance().undo();
undos++;
}
assertEquals(1, undos);
assertEquals(true, UndoStack.getInstance().isRedoSupported());
assertEquals(true, news.toReference().resolve().isFlagged());
}
}