package eu.dnetlib.enabling.resultset.push;

import static org.junit.Assert.*; // NOPMD
import static org.mockito.Mockito.*; // NOPMD

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.junit.MockitoJUnitRunner;

import com.google.common.collect.Lists;

import eu.dnetlib.enabling.resultset.ResultSetRegistry;

/**
 * test the transient push resultset.
 *
 * @author marko
 *
 */
@RunWith(MockitoJUnitRunner.class)
public class TransientPushResultSetImplTest {

	/**
	 * first test value.
	 */
	private static final String ONE = "one";

	/**
	 * second test value.
	 */
	private static final String TWO = "two";

	/**
	 * test rs id.
	 */
	private static final String RS_ID = "123";

	/**
	 * instance to be tested.
	 */
	private transient TransientPushResultSetImpl resultSet;

	/**
	 * dao mock.
	 */
	@Mock
	private transient TransientPushResultSetDao dao;

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

	/**
	 * setup class to be tested.
	 *
	 * @throws Exception
	 */
	@Before
	public void setUp() {
		resultSet = new TransientPushResultSetImpl(dao);
		resultSet.setIdentifier(RS_ID);
		resultSet.getDao(); // getter code coverage hack
	}

	/**
	 * test adding elements.
	 */
	@Test
	public void testAddElements() {
		final List<String> list = new ArrayList<String>();
		list.add(ONE);

		resultSet.addElements(list);

		verify(dao).addElements(RS_ID, list);
		assertNotNull("dummy", resultSet);
	}

	/**
	 * test get number of results.
	 */
	@Test
	public void testGetNumberOfResults() {
		when(dao.getSize(RS_ID)).thenReturn(1);

		assertEquals("check size", 1, resultSet.getNumberOfResults());
	}

	/**
	 * get result.
	 */
	@Test
	public void testGetResults() {
		final List<String> list = new ArrayList<String>();
		list.add(TWO);

		when(dao.getSize(RS_ID)).thenReturn(2);
		when(dao.getElements(RS_ID, 2, 2)).thenReturn(list);

		assertEquals("check list", TWO, resultSet.getResults(2, 2).get(0));
		assertEquals("check size", 1, resultSet.getResults(2, 2).size());
	}

	/**
	 * test when indices are out of range, trailing stuff should be skipped.
	 */
	@Test
	public void testGetResultOutOfRange() {
		final List<String> list = new ArrayList<String>();
		list.add(TWO);

		when(dao.getSize(RS_ID)).thenReturn(2);
		when(dao.getElements(RS_ID, 2, 2)).thenReturn(list);

		assertEquals("check list", TWO, resultSet.getResults(2, 2 + 1).get(0));
		assertEquals("check size", 1, resultSet.getResults(2, 2 + 1).size());
	}

	/**
	 * open.
	 */
	@Test
	public void testIsOpen() {
		assertTrue("check is open by default", resultSet.isOpen());
	}

	/**
	 * test close.
	 */
	@Test
	public void testClose() {
		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
	public void testFromAfterSize() {
		final List<String> list = new ArrayList<String>();
		list.add(TWO);

		when(dao.getSize(RS_ID)).thenReturn(2);
		when(dao.getElements(RS_ID, 2, 2)).thenReturn(list);

		resultSet.getResults(3, 2);
	}

	@Test(expected = IllegalStateException.class)
	public void testWriteClosed() {
		resultSet.close();
		resultSet.addElements(Lists.newArrayList("test"));
	}

}
