/*
 * Copyright 1999-2015 dangdang.com.
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * </p>
 */

package com.dangdang.ddframe.rdb.sharding.jdbc.adapter;

import com.dangdang.ddframe.rdb.common.base.AbstractShardingJDBCDatabaseAndTableTest;
import com.dangdang.ddframe.rdb.sharding.constant.DatabaseType;
import com.dangdang.ddframe.rdb.sharding.jdbc.core.connection.ShardingConnection;
import com.dangdang.ddframe.rdb.sharding.jdbc.util.JDBCTestSQL;
import org.junit.Ignore;
import org.junit.Test;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;

public final class ConnectionAdapterTest extends AbstractShardingJDBCDatabaseAndTableTest {

    private String sql = JDBCTestSQL.SELECT_GROUP_BY_USER_ID_SQL;

    public ConnectionAdapterTest(final DatabaseType databaseType) {
        super(databaseType);
    }

    @Test
    public void assertSetAutoCommit() throws SQLException {
        try (ShardingConnection actual = getShardingDataSource().getConnection()) {
            assertTrue(actual.getAutoCommit());
            actual.setAutoCommit(false);
            actual.createStatement().executeQuery(sql);
            assertAutoCommit(actual, false);
            actual.setAutoCommit(true);
            assertAutoCommit(actual, true);
        }
    }

    private void assertAutoCommit(final ShardingConnection actual, final boolean autoCommit) throws SQLException {
        assertThat(actual.getAutoCommit(), is(autoCommit));
        assertThat(actual.getConnections().size(), is(2));
        for (Connection each : actual.getConnections()) {
            assertThat(each.getAutoCommit(), is(autoCommit));
        }
    }

    @Test
    // TODO 缺少断言，做柔性事务时补充
    public void assertCommit() throws SQLException {
        try (ShardingConnection actual = getShardingDataSource().getConnection()) {
            actual.setAutoCommit(false);
            actual.createStatement().executeQuery(sql);
            actual.commit();
        }
    }

    @Test
    // TODO 缺少断言，做柔性事务时补充
    public void assertRollback() throws SQLException {
        try (ShardingConnection actual = getShardingDataSource().getConnection()) {
            actual.setAutoCommit(false);
            actual.createStatement().executeQuery(sql);
            actual.rollback();
        }
    }

    @Test
    public void assertClose() throws SQLException {
        try (ShardingConnection actual = getShardingDataSource().getConnection()) {
            actual.createStatement().executeQuery(sql);
            assertClose(actual, false);
            actual.close();
            assertClose(actual, true);
        }
    }

    private void assertClose(final ShardingConnection actual, final boolean closed) throws SQLException {
        assertThat(actual.isClosed(), is(closed));
        assertThat(actual.getConnections().size(), is(2));
        for (Connection each : actual.getConnections()) {
            assertThat(each.isClosed(), is(closed));
        }
    }

    @Test
    @Ignore
    public void assertSetReadOnly() throws SQLException {
        try (ShardingConnection actual = getShardingDataSource().getConnection()) {
            assertTrue(actual.isReadOnly());
            actual.setReadOnly(false);
            actual.createStatement().executeQuery(sql);
            assertReadOnly(actual, false, getCurrentDatabaseType());
            if (DatabaseType.SQLServer != getCurrentDatabaseType()) {
                actual.setReadOnly(true);
                assertReadOnly(actual, true, getCurrentDatabaseType());
            }
        }
    }

    private void assertReadOnly(final ShardingConnection actual, final boolean readOnly, final DatabaseType type) throws SQLException {
        assertThat(actual.isReadOnly(), is(readOnly));
        assertThat(actual.getConnections().size(), is(2));
        // H2数据库未实现setReadOnly方法
        if (DatabaseType.H2 != type) {
            assertThat(getShardingDataSource().getConnection().isReadOnly(), is(readOnly));
        }
    }

    @Test
    public void assertSetTransactionIsolation() throws SQLException {
        try (ShardingConnection actual = getShardingDataSource().getConnection()) {
            assertThat(actual.getTransactionIsolation(), is(Connection.TRANSACTION_READ_UNCOMMITTED));
            actual.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
            actual.createStatement().executeQuery(sql);
            assertTransactionIsolation(actual, Connection.TRANSACTION_SERIALIZABLE);
            if (DatabaseType.Oracle != getCurrentDatabaseType()) {
                actual.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
                assertTransactionIsolation(actual, Connection.TRANSACTION_READ_COMMITTED);
            }
        }
    }

    private void assertTransactionIsolation(final ShardingConnection actual, final int transactionIsolation) throws SQLException {
        assertThat(actual.getTransactionIsolation(), is(transactionIsolation));
        assertThat(actual.getConnections().size(), is(2));
        for (Connection each : actual.getConnections()) {
            assertThat(each.getTransactionIsolation(), is(transactionIsolation));
        }
    }

    @Test
    public void assertGetWarnings() throws SQLException {
        try (ShardingConnection actual = getShardingDataSource().getConnection()) {
            assertNull(actual.getWarnings());
        }
    }

    @Test
    public void assertClearWarnings() throws SQLException {
        try (ShardingConnection actual = getShardingDataSource().getConnection()) {
            actual.clearWarnings();
        }
    }

    @Test
    public void assertGetHoldability() throws SQLException {
        try (ShardingConnection actual = getShardingDataSource().getConnection()) {
            assertThat(actual.getHoldability(), is(ResultSet.CLOSE_CURSORS_AT_COMMIT));
        }
    }

    @Test
    public void assertSetHoldability() throws SQLException {
        try (ShardingConnection actual = getShardingDataSource().getConnection()) {
            actual.setHoldability(ResultSet.CONCUR_READ_ONLY);
            assertThat(actual.getHoldability(), is(ResultSet.CLOSE_CURSORS_AT_COMMIT));
        }
    }
}

@@ -966,33 +966,8 @@
 QL;%0A
-import org.junit.Ignore;%0A
 impo
@@ -1116,16 +1116,60 @@
 ers.is;%0A
+import static org.junit.Assert.assertFalse;%0A
 import s
@@ -3690,20 +3690,8 @@
 est%0A
-    @Ignore%0A
     
@@ -4494,32 +4494,94 @@
 size(), is(2));%0A
+        for (Connection each : actual.getConnections()) %7B%0A    
         // H2%E6%95%B0%E6%8D%AE%E5%BA%93
@@ -4597,32 +4597,36 @@
 dOnly%E6%96%B9%E6%B3%95%0A        
+  
+  
 if (DatabaseType
@@ -4629,17 +4629,17 @@
 Type.H2 
-!
+=
 = type) 
@@ -4656,58 +4656,96 @@
     
+ 
+   
 assert
-That(getShardingDataSource().getConnection()
+False(each.isReadOnly());%0A            %7D else %7B%0A                assertThat(each
 .isR
@@ -4762,32 +4762,46 @@
  is(readOnly));%0A
+            %7D%0A
         %7D%0A    %7D%0A

Refactor parser and integrate test cases from to do xml 11th.