package eu.dnetlib.enabling.resultset;

import static org.junit.Assert.*; // NOPMD
import static org.mockito.Mockito.*; // NOPMD by marko on 11/26/08 9:13 PM

import java.util.ArrayList;
import java.util.List;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnit44Runner;

/**
 * test the resultset concrete implementation.
 * 
 * @author marko
 * 
 */
@RunWith(MockitoJUnit44Runner.class)
public class LocalResultSetImplTest {

	/**
	 * This class could be an anonymous class, but is here to be shared among tests.
	 * 
	 * @author marko
	 * 
	 */
	private static final class TestResultSetListener implements ResultSetListener {
		/**
		 * {@inheritDoc}
		 * 
		 * @see eu.dnetlib.enabling.resultset.ResultSetListener#getResult(int, int)
		 */
		public List<String> getResult(final int fromPosition, final int toPosition) {
			final List<String> res = new ArrayList<String>();
			for (int i = fromPosition; i <= toPosition; i++)
				res.add(((Integer) (i - 1)).toString());
			return res;
		}

		public int getSize() {
			return RESULT_SIZE;
		}
	}

	/**
	 * Mockito lacks of multiple interfaces mocking.
	 * 
	 * @author marko
	 * 
	 */
	private abstract static class AbstractResultSetAware implements ResultSetListener, ResultSetAware {
	}

	/**
	 * resultset registry mock.
	 */
	@Mock
	private transient ResultSetRegistry registry;

	/**
	 * object under test.
	 */
	private transient LocalResultSetImpl resultSet;

	/**
	 * number of returned test results.
	 */
	private static final int RESULT_SIZE = 3;

	/**
	 * provides data to the resultset under test.
	 */
	private transient TestResultSetListener resultSetListener;

	/**
	 * prepare.
	 * 
	 */
	@Before
	public void setUp() {
		resultSetListener = new TestResultSetListener();
		resultSet = new LocalResultSetImpl(resultSetListener);
	}

	/**
	 * test the get number of results method.
	 */
	@Test
	public void testGetNumberOfResults() {
		assertEquals("check number of results", RESULT_SIZE, resultSet.getNumberOfResults());
	}

	/**
	 * test the get result method.
	 */
	@Test
	public void testGetResults() {
		final List<String> res = resultSet.getResults(1, RESULT_SIZE); // NOPMD by marko on 11/27/08 3:00 AM
		assertEquals("whole length", RESULT_SIZE, res.size());
		for (int i = 0; i < RESULT_SIZE; i++)
			assertEquals("check element", ((Integer) i).toString(), res.get(i));

		final List<String> res2 = resultSet.getResults(1, RESULT_SIZE - 1); // NOPMD by marko on 11/27/08 3:00 AM
		assertEquals("shorter", RESULT_SIZE - 1, res2.size());

		final List<String> res3 = resultSet.getResults(1, RESULT_SIZE + 1); // NOPMD by marko on 11/27/08 3:00 AM
		assertEquals("to out of bounds", RESULT_SIZE, res3.size());

		final List<String> res4 = resultSet.getResults(RESULT_SIZE + 1, RESULT_SIZE); // NOPMD by marko on 11/27/08 3:00 AM
		assertEquals("from out of bounds", 1, res4.size());
		
		resultSet.setOpen(true);
		final List<String> res5 = resultSet.getResults(1, RESULT_SIZE + 1); // NOPMD by marko on 11/27/08 3:00 AM
		assertEquals("to out of bounds - pass through", RESULT_SIZE + 1, res5.size());
	}

	/**
	 * test observer/observable pattern.
	 */
	@Test
	public void testDestroy() {
		resultSet.addObserver(registry);
		assertEquals("observer should be added", 1, resultSet.countObservers());

		resultSet.destroy();
		assertTrue("should be destroyed", resultSet.isDestroyed());

		assertEquals("observers should be cleared", 0, resultSet.countObservers());
		verify(registry, times(1)).update(resultSet, null);
	}

	/**
	 * test getter ... let's make code coverage happy.
	 */
	@Test
	public void testGetListener() {
		assertEquals("test getter?", resultSetListener, resultSet.getListener());
	}

	/**
	 * test setter ... let's make code coverage happy.
	 */
	@Test
	public void testSetListener() {
		assertEquals("test getter?", resultSetListener, resultSet.getListener());
		resultSet.setListener(null);
		assertNull("test setter?", resultSet.getListener());
	}

	/**
	 * test.
	 */
	@Test
	public void testResultSetAware() {
		final AbstractResultSetAware abr = mock(AbstractResultSetAware.class);
		resultSet = new LocalResultSetImpl(abr);
		assertNotNull("dummy", resultSet);
		
		verify(abr).setResultSet((ResultSet) anyObject());
		
	}

}
