// 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: TestHsqlArticlesPM.java,v 1.13 2008/02/27 08:35:58 spyromus Exp $
//
package com.salas.bb.persistence.backend;
import com.salas.bb.domain.*;
import com.salas.bb.persistence.PersistenceException;
import java.net.MalformedURLException;
import java.net.URL;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
/**
* This suite contains tests for <code>HsqlArticlesPM</code> unit.
* It covers:
* <ul>
* <li>inserting articles.</li>
* <li>updating articles.</li>
* <li>removing articles.</li>
* </ul>
*/
public class TestHsqlArticlesPM extends AbstractHsqlPersistenceTestCase
{
private HsqlArticlesPM manager;
private DirectFeed feed;
protected void setUp()
throws Exception
{
super.setUp();
// Init most modern database
initManager("/resources");
manager = new HsqlArticlesPM(pm);
// Prepare feed for use in tests
StandardGuide guide = new StandardGuide();
guide.setTitle("Test Guide");
feed = new DirectFeed();
guide.add(feed);
pm.insertGuide(guide, 0);
}
/**
* Tests adding articles.
*/
public void testInsertArticle()
throws MalformedURLException, SQLException, PersistenceException
{
StandardArticle article = new StandardArticle("D");
article.setPinned(true);
URL link = new URL("file://test");
Date date = new Date();
setSampleProperties(article, link, date);
feed.appendArticle(article);
// Insert article into database
manager.insertArticle(article);
pm.commit();
assertTrue("ID isn't set.", article.getID() != -1L);
checkLoadedArticleProperties(article);
// Check article_properties table record is created
PreparedStatement stmt = pm.getPreparedStatement("SELECT * FROM ARTICLE_PROPERTIES WHERE ARTICLEID=?");
stmt.setLong(1, article.getID());
ResultSet rs = stmt.executeQuery();
assertTrue("ARTICLE_PROPERTIES record should be added with new article.", rs.next());
assertFalse("Only one ARTICLE_PROPERTIES record per article is allowed.", rs.next());
}
/**
* Tests adding minimal articles.
*/
public void testInsertArticleMinimal()
throws MalformedURLException, PersistenceException, SQLException
{
StandardArticle article = new StandardArticle("A");
feed.appendArticle(article);
// Insert article into database
manager.insertArticle(article);
pm.commit();
assertTrue("ID isn't set.", article.getID() != -1);
// Load the whole set back and verify that article is there and
// all fields are set properly
GuidesSet set = new GuidesSet();
pm.loadGuidesSet(set);
// We don't check for presence of guides and feeds as we will learn about
// that instantly.
IFeed loadedFeed = set.getGuideAt(0).getFeedAt(0);
assertEquals("There should be the only article.", 1, loadedFeed.getArticlesCount());
IArticle loadedArticle = loadedFeed.getArticleAt(0);
assertNull("Wrong author.", loadedArticle.getAuthor());
assertNull("Wrong link.", loadedArticle.getLink());
assertNull("Wrong publication date.", loadedArticle.getPublicationDate());
assertNull("Wrong subject.", loadedArticle.getSubject());
assertNull("Wrong title.", loadedArticle.getTitle());
assertNotNull("Wrong text.", loadedArticle.getHtmlText());
assertFalse("Wrong read state.", loadedArticle.isRead());
assertFalse("Wrong pinned state.", loadedArticle.isPinned());
}
/**
* Tests handling of bad input when adding articles.
*/
public void testInsertArticleFailure()
throws PersistenceException, SQLException
{
// Unspecified article
try
{
manager.insertArticle(null);
fail("Article should be always specified. NPE is expected.");
} catch (NullPointerException e)
{
// Expected
}
// Article assigned to transient feed.
DirectFeed transientFeed = new DirectFeed();
StandardArticle article = new StandardArticle("");
transientFeed.appendArticle(article);
try
{
manager.insertArticle(article);
fail("Article is assigned to transient feed. ISE is expected.");
} catch (IllegalStateException e)
{
// Expected
}
// Save article to test the case when we are inserting it twice
article = new StandardArticle("");
feed.appendArticle(article);
manager.insertArticle(article);
// Article is already in database
try
{
manager.insertArticle(article);
fail("Article is already in database. ISE is expected.");
} catch (IllegalStateException e)
{
// Expected
}
// Remove everything from the feed
feed.setPurgeLimit(0);
feed.clean();
feed.setPurgeLimit(-1);
// Article is of unsupported type
IArticle unsupportedTypeArticle = new UnsupportedTypeArticle();
feed.appendArticle(unsupportedTypeArticle);
try
{
manager.insertArticle(unsupportedTypeArticle);
fail("Article has unsupported type. PM knows nothing about it. IAE is expected.");
} catch (IllegalArgumentException e)
{
// Expected
}
// Article isn't assigned to feed
StandardArticle unassignedArticle = new StandardArticle("");
try
{
manager.insertArticle(unassignedArticle);
fail("Article isn't assigned to the feed. ISE is expected.");
} catch (IllegalStateException e)
{
// Expected
}
}
/**
* Tests updating articles.
*/
public void testUpdateArticle()
throws PersistenceException, MalformedURLException, SQLException
{
StandardArticle article = addSampleArticle();
// Update all fields
URL link = new URL("file://test");
Date date = new Date();
setSampleProperties(article, link, date);
// Put the updates in database
manager.updateArticle(article);
checkLoadedArticleProperties(article);
}
/**
* Adds a sample article.
*
* @return article.
*
* @throws SQLException if database fails.
*/
private StandardArticle addSampleArticle()
throws SQLException
{
// Add sample article
StandardArticle article = new StandardArticle("D");
feed.appendArticle(article);
manager.insertArticle(article);
pm.commit();
return article;
}
/**
* Tests handling of bad input when updating articles.
*/
public void testUpdateArticleFailure()
throws PersistenceException, SQLException
{
// Unspecified article
try
{
manager.updateArticle(null);
fail("Article should be always specified. NPE is expected.");
} catch (NullPointerException e)
{
// Expected
}
// Article isn't in database
StandardArticle article = new StandardArticle("");
disableLogging(HsqlArticlesPM.class);
try
{
manager.updateArticle(article);
} catch (IllegalStateException e)
{
fail("Article is not in database, but ISE is replaced with log message.");
} finally
{
enableLogging(HsqlArticlesPM.class);
}
// Article is of unsupported type
IArticle unsupportedTypeArticle = new UnsupportedTypeArticle();
unsupportedTypeArticle.setID(1);
feed.appendArticle(unsupportedTypeArticle);
try
{
manager.updateArticle(unsupportedTypeArticle);
fail("Article has unsupported type. PM knows nothing about it. IAE is expected.");
} catch (IllegalArgumentException e)
{
// Expected
}
}
/** Tests updating the properties. */
public void testUpdateArticleProperties()
throws SQLException, PersistenceException
{
StandardArticle article = addSampleArticle();
// Update article sentiment counts
int positive = 2;
int negative = 3;
article.setSentimentsCounts(positive, negative);
manager.updateArticleProperties(article);
IArticle loadedArticle = getTheOnlyArticle();
assertEquals(positive, loadedArticle.getPositiveSentimentsCount());
assertEquals(negative, loadedArticle.getNegativeSentimentsCount());
}
/**
* Tests removing articles.
*/
public void testRemoveArticle()
throws PersistenceException, SQLException
{
// Add sample article
StandardArticle article = new StandardArticle("");
feed.appendArticle(article);
manager.insertArticle(article);
pm.commit();
// Remove the article
manager.removeArticle(article);
pm.commit();
assertEquals("ID of removed article should be turned -1.", -1, article.getID());
// Load the whole set back and verify that article is there and
// all fields are set properly
GuidesSet set = new GuidesSet();
pm.loadGuidesSet(set);
// We don't check for presence of guides and feeds as we will learn about
// that instantly.
IFeed loadedFeed = set.getGuideAt(0).getFeedAt(0);
assertEquals("Feed should contain 0 articles.", 0, loadedFeed.getArticlesCount());
}
/**
* Tests handling of bad input when removing articles.
*/
public void testRemoveArticleFailure()
throws PersistenceException, SQLException
{
try
{
manager.removeArticle(null);
fail("Article should be specified. NPE is expected.");
} catch (NullPointerException e)
{
// Expected
}
StandardArticle transientArticle = new StandardArticle("");
disableLogging(HsqlArticlesPM.class);
try
{
manager.removeArticle(transientArticle);
} catch (IllegalStateException e)
{
fail("Article is transient and cannot be removed, but ISE is replaced with log message.");
} finally
{
enableLogging(HsqlArticlesPM.class);
}
}
// ---------------------------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------------------------
/**
* Sets sample properties to the article.
*
* @param aArticle article.
* @param aLink link.
* @param aDate publication date.
*/
private static void setSampleProperties(StandardArticle aArticle, URL aLink, Date aDate)
{
aArticle.setAuthor("A");
aArticle.setLink(aLink);
aArticle.setPublicationDate(aDate);
aArticle.setRead(true);
aArticle.setPinned(true);
aArticle.setSubject("B");
aArticle.setTitle("C");
aArticle.computeSimpleMatchKey();
}
/**
* Makes sure that all of the articles properties set correctly.
*
* @param article article to check against.
*
* @throws PersistenceException if persistence fails.
*/
private void checkLoadedArticleProperties(IArticle article)
throws PersistenceException
{
IArticle loadedArticle = getTheOnlyArticle();
assertEquals(article, loadedArticle);
assertEquals(article.isPinned(), loadedArticle.isPinned());
assertEquals(article.getPlainText(), loadedArticle.getPlainText());
}
/**
* Returns the only article from the only feed and the only guide.
*
* @return article.
*
* @throws PersistenceException if DB fails.
*/
private IArticle getTheOnlyArticle()
throws PersistenceException
{
// Load the whole set back and verify that article is there and
// all fields are set properly
GuidesSet set = new GuidesSet();
pm.loadGuidesSet(set);
// We don't check for presence of guides and feeds as we will learn about
// that instantly.
IFeed loadedFeed = set.getGuideAt(0).getFeedAt(0);
assertEquals("There should be the only article.", 1, loadedFeed.getArticlesCount());
IArticle loadedArticle = loadedFeed.getArticleAt(0);
return loadedArticle;
}
/**
* This article class is used to simulate article of unsupported type. The
* persistence manager knows nothing about how to store it in database and
* this is exactly what we need for failure tests.
*/
private static class UnsupportedTypeArticle extends AbstractArticle
{
/**
* Returns HTML version of article text.
*
* @return HTML version of text.
*/
public String getHtmlText()
{
return null;
}
}
}