diff --git a/jOOQ/src/main/java/org/jooq/tools/jdbc/MockDataProvider.java b/jOOQ/src/main/java/org/jooq/tools/jdbc/MockDataProvider.java index 156c438f37..0eea3e3129 100644 --- a/jOOQ/src/main/java/org/jooq/tools/jdbc/MockDataProvider.java +++ b/jOOQ/src/main/java/org/jooq/tools/jdbc/MockDataProvider.java @@ -130,11 +130,11 @@ public interface MockDataProvider { * * * - * @param context The execution context. + * @param ctx The execution context. * @return The execution results. This should be non-null and non-empty, as * every execution is expected to return at least one result. * @throws SQLException A SQLException that is passed through * to jOOQ. */ - MockResult[] execute(MockExecuteContext context) throws SQLException; + MockResult[] execute(MockExecuteContext ctx) throws SQLException; } diff --git a/jOOQ/src/main/java/org/jooq/tools/jdbc/MockExecuteContext.java b/jOOQ/src/main/java/org/jooq/tools/jdbc/MockExecuteContext.java index 942e8febf9..8ae1e576c8 100644 --- a/jOOQ/src/main/java/org/jooq/tools/jdbc/MockExecuteContext.java +++ b/jOOQ/src/main/java/org/jooq/tools/jdbc/MockExecuteContext.java @@ -182,7 +182,7 @@ public class MockExecuteContext { * @return The single (or first "single batch") set of bind variables. */ public Object[] getBindings() { - return bindings[0]; + return (bindings != null && bindings.length > 0) ? bindings[0] : new Object[0]; } /** diff --git a/jOOQ/src/test/java/org/jooq/test/AbstractTest.java b/jOOQ/src/test/java/org/jooq/test/AbstractTest.java index bcaa78529c..2955ed4175 100644 --- a/jOOQ/src/test/java/org/jooq/test/AbstractTest.java +++ b/jOOQ/src/test/java/org/jooq/test/AbstractTest.java @@ -35,12 +35,18 @@ */ package org.jooq.test; +import static org.jooq.test.data.Table1.FIELD_ID1; +import static org.jooq.test.data.Table1.FIELD_NAME1; +import static org.jooq.test.data.Table1.TABLE1; + import java.sql.PreparedStatement; import org.jooq.BindContext; import org.jooq.RenderContext; +import org.jooq.Result; import org.jooq.SQLDialect; import org.jooq.impl.Executor; +import org.jooq.test.data.Table1Record; import org.jooq.util.oracle.OracleDataType; import org.jmock.Mockery; @@ -55,9 +61,12 @@ import org.junit.BeforeClass; */ public abstract class AbstractTest { - protected Mockery context; - protected PreparedStatement statement; - protected Executor create; + protected Mockery context; + protected PreparedStatement statement; + protected Executor create; + protected Result resultEmpty; + protected Result resultOne; + protected Result resultTwo; @BeforeClass public static void init() throws Exception { @@ -72,6 +81,24 @@ public abstract class AbstractTest { context = new Mockery(); statement = context.mock(PreparedStatement.class); create = new Executor(SQLDialect.ORACLE); + + resultEmpty = create.newResult(TABLE1); + + resultOne = create.newResult(TABLE1); + resultOne.add(create.newRecord(TABLE1)); + resultOne.get(0).setValue(FIELD_ID1, 1); + resultOne.get(0).setValue(FIELD_NAME1, "1"); + resultOne.get(0).changed(false); + + resultTwo = create.newResult(TABLE1); + resultTwo.add(create.newRecord(TABLE1)); + resultTwo.add(create.newRecord(TABLE1)); + resultTwo.get(0).setValue(FIELD_ID1, 2); + resultTwo.get(0).setValue(FIELD_NAME1, "2"); + resultTwo.get(0).changed(false); + resultTwo.get(1).setValue(FIELD_ID1, 3); + resultTwo.get(1).setValue(FIELD_NAME1, "3"); + resultTwo.get(1).changed(false); } @After diff --git a/jOOQ/src/test/java/org/jooq/test/MockTest.java b/jOOQ/src/test/java/org/jooq/test/MockTest.java index d429990815..6956a3e68a 100644 --- a/jOOQ/src/test/java/org/jooq/test/MockTest.java +++ b/jOOQ/src/test/java/org/jooq/test/MockTest.java @@ -38,6 +38,7 @@ package org.jooq.test; import static java.util.Arrays.asList; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNull; +import static junit.framework.Assert.fail; import static org.jooq.test.data.Table1.FIELD_ID1; import static org.jooq.test.data.Table1.FIELD_NAME1; import static org.jooq.test.data.Table1.TABLE1; @@ -45,9 +46,12 @@ import static org.jooq.test.data.Table1.TABLE1; import java.sql.SQLException; import java.util.List; +import org.jooq.InsertResultStep; +import org.jooq.Query; import org.jooq.Record; import org.jooq.Result; import org.jooq.SQLDialect; +import org.jooq.exception.DataAccessException; import org.jooq.impl.Executor; import org.jooq.test.data.Table1; import org.jooq.test.data.Table1Record; @@ -84,7 +88,7 @@ public class MockTest extends AbstractTest { execute0(ctx); return new MockResult[] { - new MockResult(0, create.newResult(Table1.TABLE1)) + new MockResult(0, resultEmpty) }; } } @@ -94,7 +98,7 @@ public class MockTest extends AbstractTest { Executor e = new Executor(new MockConnection(new SingleResult()), SQLDialect.H2); Result result = e.fetch("select ?, ? from dual", 1, 2); - assertEquals(2, result.size()); + assertEquals(1, result.size()); assertEquals(3, result.fields().length); for (int i = 0; i < 3; i++) { @@ -103,11 +107,8 @@ public class MockTest extends AbstractTest { } assertEquals(1, (int) result.getValue(0, FIELD_ID1)); - assertEquals(2, (int) result.getValue(1, FIELD_ID1)); assertEquals("1", result.getValue(0, FIELD_NAME1)); - assertEquals("2", result.getValue(1, FIELD_NAME1)); assertNull(result.getValue(0, Table1.FIELD_DATE1)); - assertNull(result.getValue(1, Table1.FIELD_DATE1)); } class SingleResult extends AbstractResult { @@ -115,17 +116,8 @@ public class MockTest extends AbstractTest { public MockResult[] execute(MockExecuteContext ctx) throws SQLException { execute0(ctx); - Result result = create.newResult(TABLE1); - result.add(create.newRecord(TABLE1)); - result.add(create.newRecord(TABLE1)); - - result.get(0).setValue(FIELD_ID1, 1); - result.get(1).setValue(FIELD_ID1, 2); - result.get(0).setValue(FIELD_NAME1, "1"); - result.get(1).setValue(FIELD_NAME1, "2"); - return new MockResult[] { - new MockResult(0, result) + new MockResult(0, resultOne) }; } } @@ -164,22 +156,9 @@ public class MockTest extends AbstractTest { public MockResult[] execute(MockExecuteContext ctx) throws SQLException { execute0(ctx); - Result result1 = create.newResult(TABLE1); - Result result2 = create.newResult(TABLE1); - result1.add(create.newRecord(TABLE1)); - result2.add(create.newRecord(TABLE1)); - result2.add(create.newRecord(TABLE1)); - - result1.get(0).setValue(FIELD_ID1, 1); - result2.get(0).setValue(FIELD_ID1, 2); - result2.get(1).setValue(FIELD_ID1, 3); - result1.get(0).setValue(FIELD_NAME1, "1"); - result2.get(0).setValue(FIELD_NAME1, "2"); - result2.get(1).setValue(FIELD_NAME1, "3"); - return new MockResult[] { - new MockResult(0, result1), - new MockResult(0, result2), + new MockResult(0, resultOne), + new MockResult(0, resultTwo), }; } } @@ -195,4 +174,131 @@ public class MockTest extends AbstractTest { assertEquals(asList(1, 2), asList(ctx.getBindings())); } } + + @Test + public void testBatchSingle() { + Executor e = new Executor(new MockConnection(new BatchSingle()), SQLDialect.H2); + + int[] result = + e.batch( + e.query("insert into x values(1)"), + e.query("insert into x values(2)") + ).execute(); + + assertEquals(2, result.length); + assertEquals(0, result[0]); + assertEquals(1, result[1]); + } + + class BatchSingle implements MockDataProvider { + + @Override + public MockResult[] execute(MockExecuteContext ctx) throws SQLException { + assertEquals(2, ctx.getBatchSQL().length); + assertEquals("insert into x values(1)", ctx.getBatchSQL()[0]); + assertEquals("insert into x values(2)", ctx.getBatchSQL()[1]); + assertEquals("insert into x values(1)", ctx.getSQL()); + + assertEquals(0, ctx.getBatchBindings().length); + assertEquals(asList(), asList(ctx.getBindings())); + + return new MockResult[] { + new MockResult(0, null), + new MockResult(1, null) + }; + } + } + + @Test + public void testBatchMultiple() { + Executor e = new Executor(new MockConnection(new BatchMultiple()), SQLDialect.H2); + + Query query = e.query("insert into x values(?, ?)", null, null); + + int[] result = + e.batch(query) + .bind(1, 2) + .bind(3, 4) + .execute(); + + assertEquals(2, result.length); + assertEquals(0, result[0]); + assertEquals(1, result[1]); + } + + class BatchMultiple implements MockDataProvider { + + @Override + public MockResult[] execute(MockExecuteContext ctx) throws SQLException { + assertEquals(1, ctx.getBatchSQL().length); + assertEquals("insert into x values(?, ?)", ctx.getBatchSQL()[0]); + assertEquals("insert into x values(?, ?)", ctx.getSQL()); + + assertEquals(2, ctx.getBatchBindings().length); + assertEquals(asList(1, 2), asList(ctx.getBatchBindings()[0])); + assertEquals(asList(3, 4), asList(ctx.getBatchBindings()[1])); + assertEquals(asList(1, 2), asList(ctx.getBindings())); + + return new MockResult[] { + new MockResult(0, null), + new MockResult(1, null) + }; + } + } + + @Test + public void testException() { + Executor e = new Executor(new MockConnection(new Exceptional()), SQLDialect.H2); + + Query query = e.query("insert into x values(1)"); + + try { + query.execute(); + fail(); + } + catch (DataAccessException expected) { + assertEquals("Expected", expected.getCause().getMessage()); + } + } + + class Exceptional implements MockDataProvider { + + @Override + public MockResult[] execute(MockExecuteContext ctx) throws SQLException { + throw new SQLException("Expected"); + } + } + + @Test + public void testInsertReturning() { + + // Note: INSERT .. RETURNING is hard to mock for all dialects... + Executor e = new Executor(new MockConnection(new InsertReturning()), SQLDialect.ORACLE); + + InsertResultStep query = e + .insertInto(TABLE1, FIELD_ID1) + .values(1) + .returning(); + + assertEquals(1, query.execute()); + Table1Record record = query.fetchOne(); + + assertEquals(1, (int) record.getValue(FIELD_ID1)); + assertEquals("1", record.getValue(FIELD_NAME1)); + } + + class InsertReturning implements MockDataProvider { + + @Override + public MockResult[] execute(MockExecuteContext ctx) throws SQLException { + assertEquals(1, ctx.getBatchSQL().length); + assertEquals(1, ctx.getBatchBindings().length); + assertEquals(asList(1), asList(ctx.getBatchBindings()[0])); + assertEquals(asList(1), asList(ctx.getBindings())); + + return new MockResult[] { + new MockResult(1, resultOne) + }; + } + } }