package dao;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.stub;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.junit.Before;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

public class DatabaseExampleTest {

	DatabaseExample databaseExample = null;
	Connection conn = null;
	
	List<Object[]> records = null;
	Iterator<Object[]> iterator = null;
	Object[] currentRecord = null;
	
	@Before
	public void setUp() throws Exception {
		databaseExample = new DatabaseExample();
		conn = mock(Connection.class);
		Statement statement = mock(Statement.class);
		ResultSet resultSet = setupResultSet();

		stub(statement.executeQuery("SELECT no, name, point FROM testTable" )).toReturn(resultSet);
		stub(statement.executeQuery("SELECT no, name, point FROM testTable2" )).toReturn(resultSet);
		stub(conn.createStatement()).toReturn(statement);
	}

	@Test
	public void testReadAbc() throws SQLException {
		
		records = new ArrayList<Object[]>();
		records.add(new Object[]{3, "abc", 2.0f});
		
		assertEquals("result rows(1): 3, abc, 2.0\n", databaseExample.readAbc(conn, "testTable"));
		
		assertEquals("result rows(1): 3, abc, 2.0\n", databaseExample.readAbc(conn, "testTable2"));
	}

	@Test
	public void testReadAbc2() throws SQLException {
		
		records = new ArrayList<Object[]>();
		records.add(new Object[]{3, "abc", 2.0f});
		records.add(new Object[]{1, "john", 1.1f});
		records.add(new Object[]{11, "ted", 4.0f});

		String resultString = "result rows(1): 3, abc, 2.0\n"
			+ "result rows(2): 1, john, 1.1\n"
			+ "result rows(3): 11, ted, 4.0\n";

		assertEquals(resultString, databaseExample.readAbc(conn, "testTable"));
		
	}
	

	private ResultSet setupResultSet() throws SQLException {
		ResultSet rs = mock(ResultSet.class);
		
		stub(rs.next()).toAnswer(new Answer<Boolean>(){
			public Boolean answer(InvocationOnMock invocation) throws Throwable {
				if ( iterator == null)
					iterator = records.iterator();
				if ( iterator.hasNext() ) {
					currentRecord = iterator.next();
					return  true;
				} else {
					currentRecord = null;
					iterator = null;
					return false;
				}
			}
		});
		
		stub(rs.getInt("no")).toAnswer( new Answer<Integer>(){
			public Integer answer(InvocationOnMock invocation) throws Throwable {
				if ( currentRecord == null ) 
					throw new SQLException("access fields is empty");
				return ((Integer)currentRecord[0]).intValue();
			}
		});

		stub(rs.getString("name")).toAnswer( new Answer<String>(){
			public String answer(InvocationOnMock invocation) throws Throwable {

				if ( currentRecord == null ) 
					throw new SQLException("access fields is empty");
				return (String)currentRecord[1];
			}
		});

		stub(rs.getFloat("point")).toAnswer( new Answer<Float>(){
			public Float answer(InvocationOnMock invocation) throws Throwable {
				if ( currentRecord == null ) 
					throw new SQLException("access fields is empty");
				return ((Float)currentRecord[2]).floatValue();
			}
		});
		
		return rs;
	}
}
