/*
* Copyright 2010, Andrew M Gibson
*
* www.andygibson.net
*
* This file is part of DataValve.
*
* DataValve is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* DataValve 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 Lesser General Public License for more details.
*
*
* You should have received a copy of the GNU Lesser General Public License
* along with DataValve. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.fluttercode.datavalve.testing.junit;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.NotSerializableException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Iterator;
import java.util.List;
import junit.framework.TestCase;
import org.fluttercode.datafactory.impl.DataFactory;
import org.fluttercode.datavalve.dataset.ObjectDataset;
/**
*
* This class is an abstract class that implements a set of tests against an
* {@link ObjectDataset} interface. You just need to subclass this and provide
* an implementation and the number of records in the dataset and this will test the
* pagination handling and other features of the dataset.
* </p>
*
* @author Andy Gibson
*
* @param <T>
*/
public abstract class AbstractObjectDatasetJUnitTest<T> extends TestCase
implements Serializable {
private static final long serialVersionUID = 1L;
private static DataFactory dataFactory = new DataFactory();
public abstract ObjectDataset<T> buildObjectDataset();
public abstract int getDataRowCount();
public static DataFactory getDataFactory() {
return dataFactory;
}
/**
* Test that the data row count is at least 30 (3 pages * 10);
*/
public void testRowCount() {
boolean hasEnoughRows = getDataRowCount() >= 30;
if (!hasEnoughRows) {
throw new RuntimeException(
"you must have at least 30 rows of data to use the built-in Object dataset tests");
}
}
public void testBuilder() {
ObjectDataset<T> ds = buildObjectDataset();
assertNotNull(ds);
}
/**
* Test isPreviousAvailable as soon as we create a dataset with no paging
*/
public void testPreviousNoRead() {
ObjectDataset<T> ds = buildObjectDataset();
assertEquals(false, ds.isPreviousAvailable());
}
/**
* Test isNextAvailable as soon as we create a dataset with no paging
*/
public void testNextNoRead() {
ObjectDataset<T> ds = buildObjectDataset();
// this should be false since paging is not enabled by default, hence it
// is all one big page
assertEquals(false, ds.isNextAvailable());
}
/**
* Test isPreviousAvailable after performing a result set read with pagining
*/
public void testPreviousPagedNoRead() {
ObjectDataset<T> ds = buildObjectDataset();
ds.setMaxRows(10);
assertEquals(false, ds.isPreviousAvailable());
}
/**
* Test isNextAvailable after performing a result set read with pagining
*/
public void testNextPagedNoRead() {
ObjectDataset<T> ds = buildObjectDataset();
ds.setMaxRows(10);
assertEquals(true, ds.isNextAvailable());
}
/**
* Check the result count matches the data row count provided by the
* developer
*/
public void testResultCount() {
ObjectDataset<T> ds = buildObjectDataset();
assertEquals(getDataRowCount(), ds.getResultCount().intValue());
}
/**
* Check the number of results returned matches the data row count provided
* by the developer
*/
public void testActualResultCount() {
ObjectDataset<T> ds = buildObjectDataset();
List<T> results = ds.getResultList();
assertEquals(ds.getResultCount().intValue(), results.size());
assertEquals(getDataRowCount(), results.size());
}
public void testNextDifferentResults() {
ObjectDataset<T> ds = buildObjectDataset();
ds.setMaxRows(10);
List<T> oldResults = ds.getResultList();
assertEquals(oldResults.size(), ds.getMaxRows().intValue());
ds.next();
assertEquals(10, ds.getFirstResult());
List<T> results = ds.getResultList();
// check results are not the same and we have a different result set.
for (int i = 0; i < 10; i++) {
assertNotSame(oldResults.get(i), results.get(i));
}
}
public void testNullingMaxRows() {
// test we can set the maxRows value to null after it has been set and
// the query will come back correct
ObjectDataset<T> ds = buildObjectDataset();
ds.setMaxRows(10);
List<T> oldResults = ds.getResultList();
assertEquals(oldResults.size(), ds.getMaxRows().intValue());
ds.setMaxRows(null);
List<T> newResults = ds.getResultList();
assertNotSame(oldResults.size(), newResults.size());
assertEquals(getDataRowCount(), newResults.size());
}
/**
* Tests the expected result count by fetching the results till we run out
*/
public void testResultCountByFetching() {
int count = 0;
ObjectDataset<T> ds = buildObjectDataset();
ds.setMaxRows(10);
List<T> results = ds.getResultList();
count += results.size();
while (ds.isNextAvailable()) {
ds.next();
results = ds.getResultList();
count += results.size();
}
assertEquals(getDataRowCount(), count);
assertEquals(getDataRowCount(), ds.getResultCount().intValue());
}
/**
* Check the multi page flag is set when we have multiple pages
*/
public void testIsMultiPageFlagPositive() {
ObjectDataset<T> ds = buildObjectDataset();
ds.setMaxRows(10); // we should have 30+ rows
assertEquals(true, ds.isMultiPage());
}
/**
* Check the multi page flag is not set when we don't have multiple pages.
*/
public void testIsMultiPageFlagNegative() {
ObjectDataset<T> ds = buildObjectDataset();
ds.setMaxRows(ds.getResultCount());
assertEquals(false, ds.isMultiPage());
}
/**
* Check that the page count is correct for different page sizes and also
* when maxResult = 0 and we have no paging (check 1 is returned)
*/
public void testPageCountSize() {
ObjectDataset<T> ds = buildObjectDataset();
int rowCount = getDataRowCount();
for (int i = 1; i < 30; i++) {
ds.setMaxRows(i); // we should have 30+ rows
int pages = ds.getPageCount();
assertTrue(pages * ds.getMaxRows() >= rowCount);
assertTrue((pages * ds.getMaxRows()) - ds.getMaxRows() < rowCount);
}
}
/**
* Check that the page numbers increase when doing next
*/
public void testGetPageNext() {
ObjectDataset<T> ds = buildObjectDataset();
ds.setMaxRows(10);
assertEquals(1, ds.getPage());
ds.next();
assertEquals(2, ds.getPage());
ds.next();
assertEquals(3, ds.getPage());
}
/**
* Check that the page numbers decrease when doing previous
*/
public void testGetPagePrevious() {
ObjectDataset<T> ds = buildObjectDataset();
ds.setMaxRows(10);
ds.setFirstResult(20);
assertEquals(3, ds.getPage());
ds.previous();
assertEquals(2, ds.getPage());
ds.previous();
assertEquals(1, ds.getPage());
}
/**
* Check that the page numbers increase when doing next/previous
*/
public void testGetPageNoPagination() {
ObjectDataset<T> ds = buildObjectDataset();
ds.setMaxRows(10);
assertEquals(1, ds.getPage());
ds.next();
assertEquals(2, ds.getPage());
ds.next();
assertEquals(3, ds.getPage());
ds.previous();
assertEquals(2, ds.getPage());
ds.previous();
assertEquals(1, ds.getPage());
ds.previous();
assertEquals(1, ds.getPage());
}
/**
* Tests what happens when firstResult * pageSize > result count. An empty
* list should be returned.
*/
public void testReadingBeyondResults() {
ObjectDataset<T> ds = buildObjectDataset();
ds.setFirstResult(getDataRowCount() + 10);
ds.setMaxRows(10);
List<T> results = ds.getResultList();
assertEquals(0, results.size());
assertEquals(false, ds.isNextAvailable());
assertEquals(true, ds.isPreviousAvailable());
}
/**
* Tests the next flag without reading the results.
*/
public void testNextFlagsNoRead() {
ObjectDataset<T> ds = buildObjectDataset();
ds.setMaxRows(10);
// assume we have tested page count
int pageCount = ds.getPageCount();
for (int i = 0; i < pageCount - 1; i++) {
assertEquals(true, ds.isNextAvailable());
ds.next();
}
assertEquals(false, ds.isNextAvailable());
}
/**
* Tests the previous flag without reading the results.
*/
public void testPreviousFlagsNoRead() {
ObjectDataset<T> ds = buildObjectDataset();
ds.setMaxRows(10);
// assume we have tested page count
int pageCount = ds.getPageCount();
assertEquals(false, ds.isPreviousAvailable());
for (int i = 0; i < pageCount; i++) {
ds.next();
assertEquals(true, ds.isPreviousAvailable());
}
}
/**
* Test the for each iterator without paging
*/
public void testForEachIteratorNonPaged() {
ObjectDataset<T> ds = buildObjectDataset();
int count = 0;
Object old = null;
for (T object : ds) {
assertNotNull(object);
assertNotSame(old, object);
old = object;
count++;
}
assertEquals(getDataRowCount(), count);
}
/**
* Test the for each iterator with paging
*/
public void testForEachIteratorPaged() {
ObjectDataset<T> ds = buildObjectDataset();
ds.setMaxRows(10);
int count = 0;
Object old = null;
for (T object : ds) {
assertNotNull(object);
assertNotSame(old, object);
old = object;
count++;
}
assertEquals(getDataRowCount(), count);
}
/**
* Test the for each iterator without paging and an offset at the start
*/
public void testForEachIteratorNonPagedStartingOffset() {
ObjectDataset<T> ds = buildObjectDataset();
ds.setFirstResult(22);
ds.getResultList();
int count = 0;
Object old = null;
for (T object : ds) {
assertNotNull(object);
assertNotSame(old, object);
old = object;
count++;
}
assertEquals(getDataRowCount(), count);
}
/**
* Test the for each iterator with paging and with an offset at the start
*/
public void testForEachIteratorPagedStartingOffset() {
ObjectDataset<T> ds = buildObjectDataset();
ds.setMaxRows(10);
ds.setFirstResult(22);
ds.getResultList();
int count = 0;
Object old = null;
for (T object : ds) {
assertNotNull(object);
assertNotSame(old, object);
old = object;
count++;
}
assertEquals(getDataRowCount(), count);
}
/**
* Test the iterator manually
*/
public void testManualIteratorPaged() {
ObjectDataset<T> ds = buildObjectDataset();
int count = 0;
for (Iterator<T> iter = ds.iterator(); iter.hasNext();) {
T object = iter.next();
assertNotNull(object);
count++;
}
assertEquals(getDataRowCount(), count);
}
/**
* Test that iterator.remove throws an exception
*/
public void testRemoveException() {
ObjectDataset<T> ds = buildObjectDataset();
try {
for (Iterator<T> iter = ds.iterator(); iter.hasNext();) {
iter.remove();
fail("iter.remove failed to throw an exception");
}
} catch (UnsupportedOperationException ex) {
// eat exception, we expected it
}
}
/**
* Set of tests to verify that when changing the order key through the and
* changeOrderKey methods, the ascending flag is being toggled correctly
*/
public void testOrderKeyToggle() {
ObjectDataset<T> ds = buildObjectDataset();
assertNull(ds.getOrderKey());
ds.changeOrderKey("ABC");
ds.changeOrderKey("ABC");
assertEquals("ABC", ds.getOrderKey());
assertFalse(ds.isOrderAscending());
ds.changeOrderKey("ABC");
assertTrue(ds.isOrderAscending());
ds.changeOrderKey("DEF");
assertTrue(ds.isOrderAscending());
ds.changeOrderKey("DEF");
assertFalse(ds.isOrderAscending());
ds.setOrderKey("XYZ");
assertFalse(ds.isOrderAscending());
}
/**
* Test the isAscending flag defaults to true when a dataset is created
*/
public void testAscendingDefault() {
ObjectDataset<T> ds = buildObjectDataset();
assertTrue(ds.isOrderAscending());
}
/**
* Test the isAscending flag is unaltered by setting the orderkey
*/
public void testAscendingTrueAfterSetOrderKey() {
ObjectDataset<T> ds = buildObjectDataset();
ds.setOrderKey("ABC");
assertTrue(ds.isOrderAscending());
ds.setOrderAscending(false);
ds.setOrderKey("ABC");
assertFalse(ds.isOrderAscending());
ds.setOrderAscending(true);
ds.setOrderKey("ABC");
assertTrue(ds.isOrderAscending());
ds.setOrderAscending(false);
ds.setOrderKey("DEF");
assertFalse(ds.isOrderAscending());
ds.setOrderAscending(true);
ds.setOrderKey("XYZ");
assertTrue(ds.isOrderAscending());
}
protected void performSerializationTest(ObjectDataset<T> dataset) {
ByteArrayOutputStream bas = new ByteArrayOutputStream(4000);
ObjectOutputStream oos;
try {
oos = new ObjectOutputStream(bas);
try {
oos.writeObject(dataset);
} catch (NotSerializableException e) {
fail("Dataset is not serializable : " + e.getMessage());
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void testSerialization() {
if (includeSerializationTest()) {
ObjectDataset<T> ds = buildObjectDataset();
performSerializationTest(ds);
}
}
public boolean includeSerializationTest() {
return true;
}
}