package com.goodworkalan.addendum.dialect; import static com.goodworkalan.addendum.Addendum.DIALECT_DOES_NOT_SUPPORT_GENERATOR; import static com.goodworkalan.addendum.Addendum.DIALECT_DOES_NOT_SUPPORT_TYPE; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import java.io.File; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import org.h2.tools.Server; import org.testng.annotations.AfterMethod; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; import com.goodworkalan.addendum.GeneratorType; import com.goodworkalan.addendum.connector.Connector; import com.goodworkalan.addendum.connector.DriverManagerConnector; import com.goodworkalan.danger.Danger; /** * Unit tests for the {@link AbstractDialect} class. * * @author Alan Gutierrez */ public class AbstractDialectTest { /** The H2 database server. */ private Server server; /** The database directory. */ private File database; /** * Create a temporary directory to store the H2 database. * * @return A temporary directory. */ private String getDatabasePath() { String property = System.getProperty("java.io.tmpdir"); do { database = new File(property, "database_" + (int) (Math.random() * 10000)); } while (!database.mkdirs()); return new File(database, "temp").toString(); } /** * Start the database server. * * @throws SQLException * For any SQL error. */ @BeforeTest public void start() throws SQLException { server = Server.createTcpServer(new String[] { "-trace" }).start(); } /** Stop the database server. */ @AfterTest public void stop() { server.stop(); } /** Delete the working database directory. */ @AfterMethod public void deleteDatabase() { if (database != null) { for (File file : database.listFiles()) { if (!file.delete()) { throw new RuntimeException(); } } if (!database.delete()) { throw new RuntimeException(); } } database = null; } /** * Create a new connector with the given H2 database path. * * @param database * The database path. * @return A new connector. */ private Connector newConnector(String database) { return new DriverManagerConnector("jdbc:h2:" + database, "test", ""); } /** * Assert that the given table exists in the database at the given * connection. * * @param connection * The database connection. * @param tableName * The table name. * @throws SQLException * For any SQL error. */ private void assertTable(Connection connection, String tableName) throws SQLException { ResultSet rs = connection.getMetaData().getTables(null, null, tableName, null); assertTrue(rs.next()); rs.close(); } /** Test creation of a table. */ // @Test public void createTable() throws SQLException, ClassNotFoundException { Class.forName("org.h2.Driver"); Connector connector = newConnector(getDatabasePath()); Connection connection = connector.open(); ConcreteDialect dialect = new ConcreteDialect(); List<Column> columns = new ArrayList<Column>(); Column a = new Column("a", int.class); columns.add(a); dialect.createTable(connection, "A", columns, Arrays.asList("a")); assertTable(connection, "A"); connection.close(); } /** Test creation of a table with no primary key. */ // @Test public void createTableNoPrimaryKey() throws SQLException, ClassNotFoundException { Class.forName("org.h2.Driver"); Connector connector = newConnector(getDatabasePath()); Connection connection = connector.open(); ConcreteDialect dialect = new ConcreteDialect(); List<Column> columns = new ArrayList<Column>(); Column a = new Column("a", int.class); columns.add(a); dialect.createTable(connection, "A", columns, Collections.<String>emptyList()); assertTable(connection, "A"); connection.close(); } /** Test definition of a column with a maximum size. */ // @Test public void defineText() { ConcreteDialect dialect = new ConcreteDialect(); Column a = new Column("a", String.class); a.setLength(Integer.MAX_VALUE); StringBuilder sql = new StringBuilder(); dialect.columnDefinition(sql, a, true); assertEquals(sql.toString(), "a TEXT"); } /** Test definition of a column with an intermediate size. */ // @Test public void defineLargerString() { ConcreteDialect dialect = new ConcreteDialect(); Column a = new Column("a", String.class); a.setLength(70000); StringBuilder sql = new StringBuilder(); dialect.columnDefinition(sql, a, true); assertEquals(sql.toString(), "a BLURDY(70000)"); } /** Test setting the default precision. */ // @Test public void defaultPrecision() { ConcreteDialect dialect = new ConcreteDialect(); Column a = new Column("a", Types.NUMERIC); a.setScale(2); StringBuilder sql = new StringBuilder(); dialect.columnDefinition(sql, a, true); assertEquals(sql.toString(), "a NUMERIC(10, 2)"); } /** Test setting the default scale. */ // @Test public void defaultScale() { ConcreteDialect dialect = new ConcreteDialect(); Column a = new Column("a", Types.NUMERIC); a.setPrecision(10); StringBuilder sql = new StringBuilder(); dialect.columnDefinition(sql, a, true); assertEquals(sql.toString(), "a NUMERIC(10, 2)"); } /** Test using a type that is unsupported by the dialect. */ // @Test(expectedExceptions = Danger.class) public void unspportedType() { try { ConcreteDialect dialect = new ConcreteDialect(); Column a = new Column("a", Types.DECIMAL); StringBuilder sql = new StringBuilder(); dialect.columnDefinition(sql, a, true); } catch (Danger e) { assertEquals(e.code, DIALECT_DOES_NOT_SUPPORT_TYPE); System.out.println(e.getMessage()); throw e; } } /** Test setting not null when not null is not allowed. */ // @Test public void cannotNull() { ConcreteDialect dialect = new ConcreteDialect(); Column a = new Column("a", Types.INTEGER); a.setNotNull(true); StringBuilder sql = new StringBuilder(); dialect.columnDefinition(sql, a, false); assertEquals(sql.toString(), "a INTEGER"); } /** Test setting not null. */ // @Test public void canNullIsNull() { ConcreteDialect dialect = new ConcreteDialect(); Column a = new Column("a", Types.INTEGER); a.setNotNull(true); StringBuilder sql = new StringBuilder(); dialect.columnDefinition(sql, a, true); assertEquals(sql.toString(), "a INTEGER NOT NULL"); } /** Test identity generator. */ // @Test public void identityGenerator() { ConcreteDialect dialect = new ConcreteDialect(); Column a = new Column("a", Types.INTEGER); a.setGeneratorType(GeneratorType.IDENTITY); StringBuilder sql = new StringBuilder(); dialect.columnDefinition(sql, a, true); assertEquals(sql.toString(), "a INTEGER AUTO_INCREMENT"); } /** Test auto generator. */ // @Test public void autoGenerator() { ConcreteDialect dialect = new ConcreteDialect(); Column a = new Column("a", Types.INTEGER); a.setGeneratorType(GeneratorType.AUTO); StringBuilder sql = new StringBuilder(); dialect.columnDefinition(sql, a, true); assertEquals(sql.toString(), "a INTEGER AUTO_INCREMENT"); } /** Test auto generator. */ // @Test public void noneGenerator() { ConcreteDialect dialect = new ConcreteDialect(); Column a = new Column("a", Types.INTEGER); a.setGeneratorType(GeneratorType.NONE); StringBuilder sql = new StringBuilder(); dialect.columnDefinition(sql, a, true); assertEquals(sql.toString(), "a INTEGER"); } /** Test using a generator that is unsupported by the dialect. */ // @Test(expectedExceptions = Danger.class) public void unspportedGenerator() { try { ConcreteDialect dialect = new ConcreteDialect(); Column a = new Column("a", Types.INTEGER); a.setGeneratorType(GeneratorType.SEQUENCE); StringBuilder sql = new StringBuilder(); dialect.columnDefinition(sql, a, true); } catch (Danger e) { assertEquals(e.code, DIALECT_DOES_NOT_SUPPORT_GENERATOR); System.out.println(e.getMessage()); throw e; } } /** Test identity generator. */ // @Test public void defaultValue() { ConcreteDialect dialect = new ConcreteDialect(); Column a = new Column("a", Types.VARCHAR); a.setDefaultValue("'"); StringBuilder sql = new StringBuilder(); dialect.columnDefinition(sql, a, true); assertEquals(sql.toString(), "a VARCHAR(225) DEFAULT ''''"); } /** Test identity generator. */ // @Test public void defaultCharValue() { ConcreteDialect dialect = new ConcreteDialect(); Column a = new Column("a", Types.CHAR); a.setDefaultValue("'"); a.setLength(16); StringBuilder sql = new StringBuilder(); dialect.columnDefinition(sql, a, true); assertEquals(sql.toString(), "a CHAR(16) DEFAULT ''''"); } /** Test column add. */ // @Test public void addColumn() throws SQLException, ClassNotFoundException { Class.forName("org.h2.Driver"); Connector connector = newConnector(getDatabasePath()); Connection connection = connector.open(); ConcreteDialect dialect = new ConcreteDialect(); List<Column> columns = new ArrayList<Column>(); Column a = new Column("a", int.class); columns.add(a); dialect.createTable(connection, "A", columns, Arrays.asList("a")); assertTable(connection, "A"); a.setName("b"); dialect.addColumn(connection, "A", a); a.setName("c"); a.setNotNull(true); a.setDefaultValue(0); dialect.addColumn(connection, "A", a); connection.close(); } /** Test column drop. */ // @Test public void dropColumn() throws SQLException, ClassNotFoundException { Class.forName("org.h2.Driver"); Connector connector = newConnector(getDatabasePath()); Connection connection = connector.open(); ConcreteDialect dialect = new ConcreteDialect(); List<Column> columns = new ArrayList<Column>(); Column a = new Column("a", int.class); columns.add(a); Column b = new Column("b", int.class); columns.add(b); dialect.createTable(connection, "A", columns, Arrays.asList("a")); assertTable(connection, "A"); dialect.dropColumn(connection, "A", "b"); connection.close(); } /** Test data insert. */ // @Test public void insert() throws SQLException, ClassNotFoundException { Class.forName("org.h2.Driver"); Connector connector = newConnector(getDatabasePath()); Connection connection = connector.open(); ConcreteDialect dialect = new ConcreteDialect(); List<Column> columns = new ArrayList<Column>(); Column a = new Column("a", int.class); columns.add(a); Column b = new Column("b", int.class); columns.add(b); dialect.createTable(connection, "A", columns, Arrays.asList("a")); assertTable(connection, "A"); dialect.insert(connection, "A", Arrays.asList("a", "b"), Arrays.asList("1", null)); connection.close(); } /** Test the unimplemented verify table method. */ // @Test public void verifyTable() throws SQLException { new ConcreteDialect().verifyTable(null, null, null); } }