package be.bendem.sqlstreams;

import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import java.sql.DriverManager;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class MappingTests {

    static private class User {
        int id;
        String email;
        String password;
        boolean activated;

        public User(int id, String email, String password) {
            this(id, email, password, false);
        }

        @MappingConstructor
        public User(int id, String email, String password, boolean activated) {
            this.id = id;
            this.email = email;
            this.password = password;
            this.activated = activated;
        }
    }

    static private class UserEmail {
        String email;
        String password;

        public UserEmail(String email, String password) {
            this.email = email;
            this.password = password;
        }
    }

    private Sql sql;

    @Before
    public void setup() throws Exception {
        sql = Sql.connect(DriverManager.getConnection("jdbc:sqlite:"));
        sql.execute("create table users (" +
            "id integer primary key autoincrement not null," +
            "email varchar(255) unique not null," +
            "password char(60) not null," +
            "activated boolean default false not null" +
        ")");

        sql.update("insert into users (email, password) values ('x@x.com', 'bcrypted password')");
    }

    @After
    public void teardown() throws Exception {
        sql.close();
    }

    @Test
    public void testSimpleMapping() {
        try (Stream<User> userStream = sql.query("select * from users", User.class)) {
            List<User> users = userStream.collect(Collectors.toList());
            Assert.assertEquals(1, users.size());
            Assert.assertEquals(1, users.get(0).id);
            Assert.assertEquals("x@x.com", users.get(0).email);
            Assert.assertEquals("bcrypted password", users.get(0).password);
        }
    }

    @Test
    public void testColumnNamesMapping() {
        try (Stream<UserEmail> userStream = sql.prepareQuery("select * from users").mapTo(UserEmail.class, "email", "password")) {
            List<UserEmail> users = userStream.collect(Collectors.toList());
            Assert.assertEquals(1, users.size());
            Assert.assertEquals("x@x.com", users.get(0).email);
            Assert.assertEquals("bcrypted password", users.get(0).password);
        }
    }

    @Test
    public void testColumnIndexesMapping() {
        try (Stream<UserEmail> userStream = sql.prepareQuery("select * from users").mapTo(UserEmail.class, 2, 3)) {
            List<UserEmail> users = userStream.collect(Collectors.toList());
            Assert.assertEquals(1, users.size());
            Assert.assertEquals("x@x.com", users.get(0).email);
            Assert.assertEquals("bcrypted password", users.get(0).password);
        }
    }

    @Test(expected = IllegalArgumentException.class)
    public void testNoConstructorMatchingColumnMapping() {
        try (PreparedQuery query = sql.prepareQuery("select * from users")) {
            query.mapTo(User.class, 1);
            Assert.fail();
        }
    }

    static class NoConstructor {}
    @Test(expected = IllegalArgumentException.class)
    public void testNoConstructorMapping() {
        try (PreparedQuery query = sql.prepareQuery("select * from users")) {
            query.mapTo(NoConstructor.class);
            Assert.fail();
        }
    }

    static class MultipleMarkedConstructor {
        @MappingConstructor
        public MultipleMarkedConstructor() {}

        @MappingConstructor
        public MultipleMarkedConstructor(Void ignore) {}
    }
    @Test(expected = IllegalArgumentException.class)
    public void testMultipleMarkedConstructors() {
        try (PreparedQuery query = sql.prepareQuery("select * from users")) {
            query.mapTo(MultipleMarkedConstructor.class);
            Assert.fail();
        }
    }

    static class MultipleNonMarkedConstructor {
        public MultipleNonMarkedConstructor(boolean bool) {}

        public MultipleNonMarkedConstructor(int i) {}
    }
    @Test(expected = IllegalArgumentException.class)
    public void testMultipleNonMarkedConstructorsWithColumnsSpecified() {
        try (PreparedQuery query = sql.prepareQuery("select * from users")) {
            query.mapTo(MultipleNonMarkedConstructor.class, 1);
            Assert.fail();
        }
    }
    @Test(expected = IllegalArgumentException.class)
    public void testMultipleNonMarkedConstructors() {
        try (PreparedQuery query = sql.prepareQuery("select * from users")) {
            query.mapTo(MultipleNonMarkedConstructor.class);
            Assert.fail();
        }
    }

    static class InvalidConstructor {
        public InvalidConstructor(User user) {}
    }
    @Test(expected = IllegalArgumentException.class)
    public void testInvalidConstructorMapping() {
        try (PreparedQuery query = sql.prepareQuery("select * from users")) {
            query.mapTo(InvalidConstructor.class);
            Assert.fail();
        }
    }

}

@@ -98,16 +98,41 @@
 Before;%0A
+import org.junit.Ignore;%0A
 import o
@@ -174,24 +174,112 @@
 verManager;%0A
+import java.time.LocalDate;%0Aimport java.time.LocalDateTime;%0Aimport java.time.LocalTime;%0A
 import java.
@@ -3120,32 +3120,1099 @@
        %7D%0A    %7D%0A%0A
+    static class DatesAndTimes %7B%0A        private final LocalTime time;%0A        private final LocalDate date;%0A        private final LocalDateTime datetime;%0A%0A        public DatesAndTimes(LocalTime time, LocalDate date, LocalDateTime datetime) %7B%0A            this.time = time;%0A            this.date = date;%0A            this.datetime = datetime;%0A        %7D%0A    %7D%0A    @Test%0A    @Ignore // https://github.com/xerial/sqlite-jdbc/issues/88%0A    public void testJava8TimeMapping() %7B%0A        try (Stream%3CDatesAndTimes%3E stream = sql.query(%22select %22%0A                + %22time('13:14:15'), %22%0A                + %22date('2016-11-13'), %22%0A                + %22datetime('2016-11-13 13:14:15')%22, DatesAndTimes.class)) %7B%0A            DatesAndTimes output = stream.findFirst().get();%0A%0A            LocalTime date = LocalTime.of(13, 14, 15);%0A            LocalDate time = LocalDate.of(2016, 11, 13);%0A            Assert.assertEquals(date, output.time);%0A            Assert.assertEquals(time, output.date);%0A            Assert.assertEquals(LocalDateTime.of(time, date), output.datetime);%0A        %7D%0A    %7D%0A%0A
     @Test(expect

Add ignored test for java.time mapping