/*
 * Copyright 2006 - 2007 the original author or authors.
 * This source code licensed under the GPL License.
 * You may not use this file except in compliance with the License.
 */
package jp.sf.bli.ss.sample.dao.impl.sample;

import java.sql.Connection;
import java.util.Iterator;
import java.util.List;

import jp.sf.bli.ss.sample.dao.SampleDao;
import jp.sf.bli.ss.sample.model.Sample;
import jp.sf.bli.testingframework.BliDbUnitTestCase;

import org.dbunit.Assertion;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.ITable;
import org.dbunit.dataset.xml.XmlDataSet;
import org.dbunit.operation.DatabaseOperation;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.dao.DataAccessException;

/**
 * テストをする際には/hsqldb/bin/runServ.batを実行しておく事
 * 
 * @author takeda 2007/02/06
 */
public class SampleDaoTest extends BliDbUnitTestCase {

    /**
     * テスト事前準備
     */
    public SampleDaoTest() throws Exception {

        ApplicationContext context = new ClassPathXmlApplicationContext(
                "applicationContext.xml" );

        this.context = context; // Springのcontextをセット
        this.truncateSql = "delete from sample "; // このテストクラスで初期化するSQL文
        this.oracleFlag = false; // oracleの場合true

    }


    /**
     * SampleDao selectAllSample 正常終了
     * 
     * <pre>
     *     [前提条件]
     *     DBに接続できる。
     *     DBUnitにてSelectする前のテーブルのデータを用意する。
     *     [テスト内容]
     *     実際にDBに本クラスから接続をしてDBUnitで用意したデータと
     *     同一のデータが帰ってきているかを確認する。
     *     [事後条件]
     *     DBUnitで用意したデータでテストに合格をする。
     * </pre>
     */
    public void testSelectALLSample01() {

        String testMethodNameStr = "testSelectALLSample01";

        logStart( testMethodNameStr );

        Connection con = null;
        SampleDao sampleDao = null;

        // ---------------------------------------------------------------------
        // テスト準備 SpringでInjectionしたDAOからConnectionを取り出す
        // ---------------------------------------------------------------------

        try {

            // DAOをインスタンス化する
            sampleDao = ( SampleDao ) this.context.getBean( "sampleDao" );

            // DAOからConnectionを取り出してテストで共通で使用する
            // Connectionを共通にしていないとassertEqualsが合わない場合がある
            SampleDaoImpl sampleDaoImpl = ( SampleDaoImpl ) sampleDao;
            con = sampleDaoImpl.getDataSource().getConnection();
            con.setAutoCommit( true );

        } catch ( Exception e ) {

            e.printStackTrace();

        }

        // ---------------------------------------------------------------------
        // テスト準備 DBを初期化して事前データを投入する
        // ---------------------------------------------------------------------

        try {

            // DBを初期化
            tableInit(con);

            // 準備データをDBに入れる

            DatabaseOperation.CLEAN_INSERT.execute( getConnection( con ),
                    new XmlDataSet( SampleDaoTest.class
                            .getResourceAsStream( "sample-prepare01.xml" ) ) );

        } catch ( Exception e ) {
            e.printStackTrace();
        }

        // ---------------------------------------------------------------------
        // テスト対象ロジックの実行
        // ---------------------------------------------------------------------

        try {

            sampleDao = ( SampleDao ) this.context.getBean( "sampleDao" );

            List sampleDaoList = sampleDao.selectAllSample();

            int countFlag = 1;

            // 期待値と実際のデータの比較

            assertEquals( sampleDaoList.size(), 3 ); // レコード数

            Iterator itr = sampleDaoList.iterator();

            while ( itr.hasNext() ) {
                Sample sample = ( Sample ) itr.next();

                switch ( countFlag ) {
                    case 1:
                        assertEquals( sample.getId().intValue(), 1 );
                        assertEquals( sample.getName(), "武田" );
                        assertEquals( sample.getAge().intValue(), 11 );
                        break;

                    case 2:
                        assertEquals( sample.getId().intValue(), 2 );
                        assertEquals( sample.getName(), "山田" );
                        assertEquals( sample.getAge().intValue(), 21 );
                        break;

                    case 3:
                        assertEquals( sample.getId().intValue(), 3 );
                        assertEquals( sample.getName(), "鈴木" );
                        assertEquals( sample.getAge().intValue(), 31 );
                        break;

                    default:
                        fail( "想定していないレコードです。" );

                }

                countFlag++;
            }

        } catch ( Exception e ) {

            e.printStackTrace();
            fail( "Exceptionを起こしてはいけません。" );

        }

        logEnd( testMethodNameStr );

    }


    /**
     * SampleDao selectAllSample 異常終了
     * 
     * <pre>
     *     [前提条件]
     *     DBに接続できる。
     *     DBUnitにてSelectする前のテーブルのデータを用意する。
     *     [テスト内容]
     *     selectAllSampleを実行するとDataAccessExceptionが
     *     発生するのでcatchする。
     *     [事後条件]
     *     failを通過しない。
     * </pre>
     */
    public void testSelectALLSampleException01() {

        String testMethodNameStr = "testSelectALLSampleException01";

        logStart( testMethodNameStr );

        // ---------------------------------------------------------------------
        // テスト対象ロジックの実行
        // ---------------------------------------------------------------------

        try {

            // ExceptionをVirtualMockにて発生させる

            DataAccessException de = new MockDataAccessException();

            addReturnValue(
                    "org.springframework.jdbc.core.support.JdbcDaoSupport",
                    "getJdbcTemplate", de );

            // テスト対象ロジックの実行

            SampleDao sampleDao = ( SampleDao ) this.context
                    .getBean( "sampleDao" );

            sampleDao.selectAllSample();

            fail( "Exceptionを起こさなくてはいけません。" );

        } catch ( Exception e ) {

            e.printStackTrace();

        }

        logEnd( testMethodNameStr );

    }


    /**
     * SampleDao testInsertSample 正常終了
     * 
     * <pre>
     *     [前提条件]
     *     DBに接続できる。
     *     DBUnitにてInsertする前のテーブルのデータを用意する。
     *     [テスト内容]
     *     事前データが入っている状態でInsertを行う。
     *     [事後条件]
     *     期待値データと一致する。
     * </pre>
     */
    public void testInsertSample01() {

        String testMethodNameStr = "testInsertSample01";

        logStart( testMethodNameStr );

        ITable expectedTable;
        ITable actualTable;
        Connection con = null;
        SampleDao sampleDao = null;

        // ---------------------------------------------------------------------
        // テスト準備 SpringでInjectionしたDAOからConnectionを取り出す
        // ---------------------------------------------------------------------

        try {

            // DAOをインスタンス化する
            sampleDao = ( SampleDao ) this.context.getBean( "sampleDao" );

            // DAOからConnectionを取り出してテストで共通で使用する
            // Connectionを共通にしていないとassertEqualsが合わない場合がある
            SampleDaoImpl sampleDaoImpl = ( SampleDaoImpl ) sampleDao;
            con = sampleDaoImpl.getDataSource().getConnection();
            con.setAutoCommit( true );

        } catch ( Exception e ) {

            e.printStackTrace();

        }

        // ---------------------------------------------------------------------
        // テスト準備 DBを初期化して事前データを投入する
        // ---------------------------------------------------------------------

        try {
            // DBを初期化
            tableInit(con);

            // 準備データをDBに入れる
            DatabaseOperation.CLEAN_INSERT.execute( getConnection( con ),
                    new XmlDataSet( SampleDaoTest.class
                            .getResourceAsStream( "sample-prepare01.xml" ) ) );
        } catch ( Exception e ) {
            e.printStackTrace();
        }

        // ---------------------------------------------------------------------
        // テスト対象ロジックの実行
        // ---------------------------------------------------------------------

        try {

            // テスト対象ロジックの実行

            Integer id = Integer.valueOf( 4 );
            String name = "佐藤";
            Integer age = Integer.valueOf( 41 );

            sampleDao.insertSample( id, name, age );

        } catch ( Exception e ) {

            e.printStackTrace();
            fail( "Exceptionを起こしてはいけません。" );

        }

        // ---------------------------------------------------------------------
        // DBの中を期待値データと比較する
        // ---------------------------------------------------------------------

        try {

            // DBから実際のデータの取得
            IDataSet databaseDataSet = getConnection(con).createDataSet();
            actualTable = databaseDataSet.getTable( "sample" );

            // 期待値データの取得
            IDataSet expectedDataSet = new XmlDataSet( SampleDaoTest.class
                    .getResourceAsStream( "sample-expected01.xml" ) );

            expectedTable = expectedDataSet.getTable( "sample" );

            // 期待値と実際のデータの比較
            Assertion.assertEquals( expectedTable, actualTable );

        } catch ( Exception e ) {

            e.printStackTrace();

        }

        logEnd( testMethodNameStr );

    }


    /**
     * SampleDao InsertSample 異常終了
     * 
     * <pre>
     *     [前提条件]
     *     DBに接続できる。
     *     DBUnitにてInsertする前のテーブルのデータを用意する。
     *     [テスト内容]
     *     実行するとDataAccessExceptionが発生するのでcatchする。
     *     [事後条件]
     *     failを通過しない。
     * </pre>
     */
    public void testInsertSampleException01() {

        String testMethodNameStr = "testInsertSampleException01";

        logStart( testMethodNameStr );

        // ---------------------------------------------------------------------
        // テスト対象ロジックの実行
        // ---------------------------------------------------------------------

        try {

            // ExceptionをVirtualMockにて発生させる

            DataAccessException de = new MockDataAccessException();

            addReturnValue(
                    "org.springframework.jdbc.core.support.JdbcDaoSupport",
                    "getJdbcTemplate", de );

            // テスト対象ロジックの実行
            SampleDao sampleDao = ( SampleDao ) this.context
                    .getBean( "sampleDao" );

            Integer id = Integer.valueOf( 4 );
            String name = "佐藤";
            Integer age = Integer.valueOf( 41 );

            sampleDao.insertSample( id, name, age );

            fail( "Exceptionを起こさなくてはいけません。" );

        } catch ( Exception e ) {

            e.printStackTrace();

        }

        logEnd( testMethodNameStr );

    }


    /**
     * SampleDao testUpdateSample 正常終了
     * 
     * <pre>
     *     [前提条件]
     *     DBに接続できる。
     *     DBUnitにてUpdateする前のテーブルのデータを用意する。
     *     [テスト内容]
     *     事前データが入っている状態でUpdateを行う。
     *     [事後条件]
     *     期待値データと一致する。
     * </pre>
     */
    public void testUpdateSample() {

        String testMethodNameStr = "testUpdateSample";

        logStart( testMethodNameStr );

        ITable expectedTable;
        ITable actualTable;
        Connection con = null;
        SampleDao sampleDao = null;

        // ---------------------------------------------------------------------
        // テスト準備 SpringでInjectionしたDAOからConnectionを取り出す
        // ---------------------------------------------------------------------

        try {

            // DAOをインスタンス化する
            sampleDao = ( SampleDao ) this.context.getBean( "sampleDao" );

            // DAOからConnectionを取り出してテストで共通で使用する
            // Connectionを共通にしていないとassertEqualsが合わない場合がある
            SampleDaoImpl sampleDaoImpl = ( SampleDaoImpl ) sampleDao;
            con = sampleDaoImpl.getDataSource().getConnection();
            con.setAutoCommit( true );

        } catch ( Exception e ) {

            e.printStackTrace();

        }

        // ---------------------------------------------------------------------
        // テスト準備 DBを初期化して事前データを投入する
        // ---------------------------------------------------------------------

        try {
            // DBを初期化
            tableInit(con);

            // 準備データをDBに入れる
            DatabaseOperation.CLEAN_INSERT.execute( getConnection( con ),
                    new XmlDataSet( SampleDaoTest.class
                            .getResourceAsStream( "sample-prepare01.xml" ) ) );
        } catch ( Exception e ) {
            e.printStackTrace();
        }

        // ---------------------------------------------------------------------
        // テスト対象ロジックの実行
        // ---------------------------------------------------------------------

        try {

            // テスト対象ロジックの実行
            Integer id = Integer.valueOf( 2 );
            String name = "山田太郎";
            Integer age = Integer.valueOf( 211 );

            sampleDao.updateSample( id, name, age );

        } catch ( Exception e ) {

            e.printStackTrace();
            fail( "Exceptionを起こしてはいけません。" );

        }

        // ---------------------------------------------------------------------
        // DBの中を期待値データと比較する
        // ---------------------------------------------------------------------

        try {

            // DBから実際のデータの取得
            IDataSet databaseDataSet = getConnection(con).createDataSet();
            actualTable = databaseDataSet.getTable( "sample" );

            // 期待値データの取得
            IDataSet expectedDataSet = new XmlDataSet( SampleDaoTest.class
                    .getResourceAsStream( "sample-expected02.xml" ) );

            expectedTable = expectedDataSet.getTable( "sample" );

            // 期待値と実際のデータの比較
            Assertion.assertEquals( expectedTable, actualTable );

        } catch ( Exception e ) {

            e.printStackTrace();

        }

        logEnd( testMethodNameStr );

    }


    /**
     * SampleDao updateSample 異常終了
     * 
     * <pre>
     *     [前提条件]
     *     DBに接続できる。
     *     [テスト内容]
     *     実行するとDataAccessExceptionが発生するのでcatchする。
     *     [事後条件]
     *     failを通過しない。
     * </pre>
     */
    public void testUpdateSampleException() {

        String testMethodNameStr = "testUpdateSampleException";

        logStart( testMethodNameStr );

        // ---------------------------------------------------------------------
        // テスト対象ロジックの実行
        // ---------------------------------------------------------------------

        try {

            // ExceptionをVirtualMockにて発生させる

            DataAccessException de = new MockDataAccessException();

            // コンストラクタでExceptionを発生させる
            addReturnValue( "jp.sf.bli.ss.sample.dao.impl.sample.UpdateSample",
                    "<init>", de );

            // テスト対象ロジックの実行
            SampleDao sampleDao = ( SampleDao ) this.context
                    .getBean( "sampleDao" );

            Integer id = Integer.valueOf( 2 );
            String name = "山田太郎";
            Integer age = Integer.valueOf( 211 );

            sampleDao.updateSample( id, name, age );

            fail( "Exceptionを起こさなくてはいけません。" );

        } catch ( Exception e ) {

            e.printStackTrace();

        }

        logEnd( testMethodNameStr );

    }


    /**
     * SampleRowMapper getResults
     * 
     * <pre>
     *     [前提条件]
     *     特になし
     *     [テスト内容]
     *     getResultsを実行してListに代入する。
     *     [事後条件]
     *     failを通過しない。
     *     Listのサイズが0。
     * </pre>
     */
    public void testSampleRowMapper() {

        String testMethodNameStr = "testSampleRowMapper";

        logStart( testMethodNameStr );

        // ---------------------------------------------------------------------
        // テスト対象ロジックの実行
        // ---------------------------------------------------------------------

        try {
            SampleRowMapper sr = new SampleRowMapper();

            if ( sr.getResults() == null ) {

                fail( "NULLが帰ってきては行けません。" );

            } else {

                List list = ( List ) sr.getResults();
                assertEquals( list.size(), 0 );
            }

        } catch ( Exception e ) {

            e.printStackTrace();

        }

        logEnd( testMethodNameStr );

    }

}
