/*
 * 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.
 */
package org.jdbi.v3.core.mapper.reflect;

import static org.assertj.core.api.Assertions.assertThat;

import org.jdbi.v3.core.rule.H2DatabaseRule;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;

public class ConstructorMapperTest {

    @Rule
    public H2DatabaseRule dbRule = new H2DatabaseRule();

    @Before
    public void setUp() throws Exception {
        dbRule.getSharedHandle()
                .registerRowMapper(ConstructorMapper.factory(ConstructorBean.class))
                .registerRowMapper(ConstructorMapper.factory(NamedParameterBean.class));
        dbRule.getSharedHandle().execute("CREATE TABLE bean (s varchar, i integer)");

        dbRule.getSharedHandle().execute("INSERT INTO bean VALUES('3', 2)");
    }

    public ConstructorBean execute(String query) {
        return dbRule.getSharedHandle().createQuery(query).mapTo(ConstructorBean.class).findOnly();
    }

    @Test
    public void testSimple() throws Exception {
        ConstructorBean bean = execute("SELECT s, i FROM bean");

        assertThat(bean.s).isEqualTo("3");
        assertThat(bean.i).isEqualTo(2);
    }

    @Test
    public void testReversed() throws Exception {
        ConstructorBean bean = execute("SELECT i, s FROM bean");

        assertThat(bean.s).isEqualTo("3");
        assertThat(bean.i).isEqualTo(2);
    }

    @Test
    public void testExtra() throws Exception {
        ConstructorBean bean = execute("SELECT 1 as ignored, i, s FROM bean");

        assertThat(bean.s).isEqualTo("3");
        assertThat(bean.i).isEqualTo(2);
    }

    @Test(expected = IllegalArgumentException.class)
    public void testDuplicate() throws Exception {
        execute("SELECT i, s, s FROM bean");
    }

    @Test(expected = IllegalArgumentException.class)
    public void testMismatch() throws Exception {
        execute("SELECT i, '7' FROM bean");
    }

    @Test
    public void testName() throws Exception {
        NamedParameterBean nb = dbRule.getSharedHandle().createQuery("SELECT 3 AS xyz")
                .mapTo(NamedParameterBean.class).findOnly();
        assertThat(nb.i).isEqualTo(3);
    }

    static class ConstructorBean {
        private final String s;
        private final int i;

        ConstructorBean(int some, String other, long constructor) {
            throw new UnsupportedOperationException("You don't belong here!");
        }

        @JdbiConstructor
        ConstructorBean(String s, int i) {
            this.s = s;
            this.i = i;
        }
    }

    static class NamedParameterBean {
        final int i;
        NamedParameterBean(@ColumnName("xyz") int i) {
            this.i = i;
        }
    }
}

@@ -769,16 +769,58 @@
 .Test;%0A%0A
+import java.beans.ConstructorProperties;%0A%0A
 public c
@@ -1177,16 +1177,111 @@
 .class))
+%0A                .registerRowMapper(ConstructorMapper.factory(ConstructorPropertiesBean.class))
 ;%0A      
@@ -2816,32 +2816,401 @@
 alTo(3);%0A    %7D%0A%0A
+    @Test%0A    public void testConstructorProperties() throws Exception %7B%0A        final ConstructorPropertiesBean cpi = dbRule.getSharedHandle()%0A                .createQuery(%22SELECT * FROM bean%22)%0A                .mapTo(ConstructorPropertiesBean.class)%0A                .findOnly();%0A        assertThat(cpi.s).isEqualTo(%223%22);%0A        assertThat(cpi.i).isEqualTo(2);%0A    %7D%0A%0A
     static class
@@ -3687,32 +3687,32 @@
 %22xyz%22) int i) %7B%0A
-
             this
@@ -3734,11 +3734,263 @@
  %7D%0A    %7D
+%0A%0A    static class ConstructorPropertiesBean %7B%0A        final String s;%0A        final int i;%0A%0A        @ConstructorProperties(%7B%22s%22, %22i%22%7D)%0A        ConstructorPropertiesBean(String x, int y) %7B%0A            this.s = x;%0A            this.i = y;%0A        %7D%0A    %7D
 %0A%7D%0A

Add test to show `@ConstructorProperties` mapping at work