package org.sqlite; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import java.io.ByteArrayInputStream; import java.nio.charset.StandardCharsets; import java.sql.Connection; import java.sql.Date; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; import java.util.StringTokenizer; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** These tests are designed to stress PreparedStatements on memory dbs. */ public class PrepStmtTest { static byte[] b1 = new byte[] {1, 2, 7, 4, 2, 6, 2, 8, 5, 2, 3, 1, 5, 3, 6, 3, 3, 6, 2, 5}; static byte[] b2 = getUtf8Bytes("To be or not to be."); static byte[] b3 = getUtf8Bytes("Question!#$%"); static String utf01 = "\uD840\uDC40"; static String utf02 = "\uD840\uDC47 "; static String utf03 = " \uD840\uDC43"; static String utf04 = " \uD840\uDC42 "; static String utf05 = "\uD840\uDC40\uD840\uDC44"; static String utf06 = "Hello World, \uD840\uDC40 \uD880\uDC99"; static String utf07 = "\uD840\uDC41 testing \uD880\uDC99"; static String utf08 = "\uD840\uDC40\uD840\uDC44 testing"; private Connection conn; private Statement stat; private static byte[] getUtf8Bytes(String str) { return str.getBytes(StandardCharsets.UTF_8); } @BeforeEach public void connect() throws Exception { conn = DriverManager.getConnection("jdbc:sqlite:"); stat = conn.createStatement(); } @AfterEach public void close() throws SQLException { stat.close(); conn.close(); } @Test public void update() throws SQLException { assertEquals(conn.prepareStatement("create table s1 (c1);").executeUpdate(), 0); PreparedStatement prep = conn.prepareStatement("insert into s1 values (?);"); prep.setInt(1, 3); assertEquals(prep.executeUpdate(), 1); assertNull(prep.getResultSet()); prep.setInt(1, 5); assertEquals(prep.executeUpdate(), 1); prep.setInt(1, 7); assertEquals(prep.executeUpdate(), 1); prep.close(); // check results with normal statement ResultSet rs = stat.executeQuery("select sum(c1) from s1;"); assertTrue(rs.next()); assertEquals(rs.getInt(1), 15); rs.close(); } @Test public void multiUpdate() throws SQLException { stat.executeUpdate("create table test (c1);"); PreparedStatement prep = conn.prepareStatement("insert into test values (?);"); for (int i = 0; i < 10; i++) { prep.setInt(1, i); prep.executeUpdate(); prep.execute(); } prep.close(); stat.executeUpdate("drop table test;"); } @Test public void emptyRS() throws SQLException { PreparedStatement prep = conn.prepareStatement("select null limit 0;"); ResultSet rs = prep.executeQuery(); assertFalse(rs.next()); rs.close(); prep.close(); } @Test public void singleRowRS() throws SQLException { PreparedStatement prep = conn.prepareStatement("select ?;"); prep.setInt(1, Integer.MAX_VALUE); ResultSet rs = prep.executeQuery(); assertTrue(rs.next()); assertEquals(rs.getInt(1), Integer.MAX_VALUE); assertEquals(rs.getString(1), Integer.toString(Integer.MAX_VALUE)); assertEquals(rs.getDouble(1), new Integer(Integer.MAX_VALUE).doubleValue(), 0.0001); assertFalse(rs.next()); rs.close(); prep.close(); } @Test public void twoRowRS() throws SQLException { PreparedStatement prep = conn.prepareStatement("select ? union all select ?;"); prep.setDouble(1, Double.MAX_VALUE); prep.setDouble(2, Double.MIN_VALUE); ResultSet rs = prep.executeQuery(); assertTrue(rs.next()); assertEquals(rs.getDouble(1), Double.MAX_VALUE, 0.0001); assertTrue(rs.next()); assertEquals(rs.getDouble(1), Double.MIN_VALUE, 0.0001); assertFalse(rs.next()); rs.close(); } @Test public void stringRS() throws SQLException { String name = "Gandhi"; PreparedStatement prep = conn.prepareStatement("select ?;"); prep.setString(1, name); ResultSet rs = prep.executeQuery(); assertEquals(-1, prep.getUpdateCount()); assertTrue(rs.next()); assertEquals(rs.getString(1), name); assertFalse(rs.next()); rs.close(); } @Test public void finalizePrep() throws SQLException { conn.prepareStatement("select null;"); System.gc(); } @Test public void set() throws SQLException { ResultSet rs; PreparedStatement prep = conn.prepareStatement("select ?, ?, ?;"); // integers prep.setInt(1, Integer.MIN_VALUE); prep.setInt(2, Integer.MAX_VALUE); prep.setInt(3, 0); rs = prep.executeQuery(); assertTrue(rs.next()); assertEquals(rs.getInt(1), Integer.MIN_VALUE); assertEquals(rs.getInt(2), Integer.MAX_VALUE); assertEquals(rs.getInt(3), 0); // strings String name = "Winston Leonard Churchill"; String fn = name.substring(0, 7), mn = name.substring(8, 15), sn = name.substring(16, 25); prep.clearParameters(); prep.setString(1, fn); prep.setString(2, mn); prep.setString(3, sn); prep.executeQuery(); assertTrue(rs.next()); assertEquals(rs.getString(1), fn); assertEquals(rs.getString(2), mn); assertEquals(rs.getString(3), sn); // mixed prep.setString(1, name); prep.setString(2, null); prep.setLong(3, Long.MAX_VALUE); prep.executeQuery(); assertTrue(rs.next()); assertEquals(rs.getString(1), name); assertNull(rs.getString(2)); assertTrue(rs.wasNull()); assertEquals(rs.getLong(3), Long.MAX_VALUE); // bytes prep.setBytes(1, b1); prep.setBytes(2, b2); prep.setBytes(3, b3); prep.executeQuery(); assertTrue(rs.next()); assertArrayEq(rs.getBytes(1), b1); assertArrayEq(rs.getBytes(2), b2); assertArrayEq(rs.getBytes(3), b3); assertFalse(rs.next()); rs.close(); // null date, time and timestamp (fix #363) prep.setDate(1, null); prep.setTime(2, null); prep.setTimestamp(3, null); rs = prep.executeQuery(); assertTrue(rs.next()); assertNull(rs.getDate(1)); assertNull(rs.getTime(2)); assertNull(rs.getTimestamp(3)); // streams ByteArrayInputStream inByte = new ByteArrayInputStream(b1); prep.setBinaryStream(1, inByte, b1.length); ByteArrayInputStream inAscii = new ByteArrayInputStream(b2); prep.setAsciiStream(2, inAscii, b2.length); byte[] b3 = utf08.getBytes(StandardCharsets.UTF_8); ByteArrayInputStream inUnicode = new ByteArrayInputStream(b3); prep.setUnicodeStream(3, inUnicode, b3.length); rs = prep.executeQuery(); assertTrue(rs.next()); assertArrayEq(b1, rs.getBytes(1)); assertEquals(new String(b2, StandardCharsets.UTF_8), rs.getString(2)); assertEquals(new String(b3, StandardCharsets.UTF_8), rs.getString(3)); assertFalse(rs.next()); rs.close(); } @Test public void colNameAccess() throws SQLException { PreparedStatement prep = conn.prepareStatement("select ? as col1, ? as col2, ? as bingo;"); prep.setNull(1, 0); prep.setFloat(2, Float.MIN_VALUE); prep.setShort(3, Short.MIN_VALUE); prep.executeQuery(); ResultSet rs = prep.executeQuery(); assertTrue(rs.next()); assertNull(rs.getString("col1")); assertTrue(rs.wasNull()); assertEquals(rs.getFloat("col2"), Float.MIN_VALUE, 0.0001); assertEquals(rs.getShort("bingo"), Short.MIN_VALUE); rs.close(); prep.close(); } @Test public void insert1000() throws SQLException { stat.executeUpdate("create table in1000 (a);"); PreparedStatement prep = conn.prepareStatement("insert into in1000 values (?);"); conn.setAutoCommit(false); for (int i = 0; i < 1000; i++) { prep.setInt(1, i); prep.executeUpdate(); } conn.commit(); ResultSet rs = stat.executeQuery("select count(a) from in1000;"); assertTrue(rs.next()); assertEquals(rs.getInt(1), 1000); rs.close(); } @Test public void getObject() throws SQLException { stat.executeUpdate( "create table testobj (" + "c1 integer, c2 float, c3, c4 varchar, c5 bit, c6, c7);"); PreparedStatement prep = conn.prepareStatement("insert into testobj values (?,?,?,?,?,?,?);"); prep.setInt(1, Integer.MAX_VALUE); prep.setFloat(2, Float.MAX_VALUE); prep.setDouble(3, Double.MAX_VALUE); prep.setLong(4, Long.MAX_VALUE); prep.setBoolean(5, false); prep.setByte(6, (byte) 7); prep.setBytes(7, b1); prep.executeUpdate(); ResultSet rs = stat.executeQuery("select c1,c2,c3,c4,c5,c6,c7 from testobj;"); assertTrue(rs.next()); assertEquals(rs.getInt(1), Integer.MAX_VALUE); assertEquals((int) rs.getLong(1), Integer.MAX_VALUE); assertEquals(rs.getFloat(2), Float.MAX_VALUE, 0.0001f); assertEquals(rs.getDouble(3), Double.MAX_VALUE, 0.0001d); assertEquals(rs.getLong(4), Long.MAX_VALUE); assertFalse(rs.getBoolean(5)); assertEquals(rs.getByte(6), (byte) 7); assertArrayEq(rs.getBytes(7), b1); assertNotNull(rs.getObject(1)); assertNotNull(rs.getObject(2)); assertNotNull(rs.getObject(3)); assertNotNull(rs.getObject(4)); assertNotNull(rs.getObject(5)); assertNotNull(rs.getObject(6)); assertNotNull(rs.getObject(7)); assertTrue(rs.getObject(1) instanceof Integer); assertTrue(rs.getObject(2) instanceof Double); assertTrue(rs.getObject(3) instanceof Double); assertTrue(rs.getObject(4) instanceof String); assertTrue(rs.getObject(5) instanceof Integer); assertTrue(rs.getObject(6) instanceof Integer); assertTrue(rs.getObject(7) instanceof byte[]); rs.close(); } @Test public void tokens() throws SQLException { /* checks for a bug where a substring is read by the driver as the * full original string, caused by my idiocyin assuming the * pascal-style string was null terminated. Thanks Oliver Randschau. */ StringTokenizer st = new StringTokenizer("one two three"); st.nextToken(); String substr = st.nextToken(); PreparedStatement prep = conn.prepareStatement("select ?;"); prep.setString(1, substr); ResultSet rs = prep.executeQuery(); assertTrue(rs.next()); assertEquals(rs.getString(1), substr); } @Test public void utf() throws SQLException { ResultSet rs = stat.executeQuery( "select '" + utf01 + "','" + utf02 + "','" + utf03 + "','" + utf04 + "','" + utf05 + "','" + utf06 + "','" + utf07 + "','" + utf08 + "';"); assertArrayEq(rs.getBytes(1), getUtf8Bytes(utf01)); assertArrayEq(rs.getBytes(2), getUtf8Bytes(utf02)); assertArrayEq(rs.getBytes(3), getUtf8Bytes(utf03)); assertArrayEq(rs.getBytes(4), getUtf8Bytes(utf04)); assertArrayEq(rs.getBytes(5), getUtf8Bytes(utf05)); assertArrayEq(rs.getBytes(6), getUtf8Bytes(utf06)); assertArrayEq(rs.getBytes(7), getUtf8Bytes(utf07)); assertArrayEq(rs.getBytes(8), getUtf8Bytes(utf08)); assertEquals(rs.getString(1), utf01); assertEquals(rs.getString(2), utf02); assertEquals(rs.getString(3), utf03); assertEquals(rs.getString(4), utf04); assertEquals(rs.getString(5), utf05); assertEquals(rs.getString(6), utf06); assertEquals(rs.getString(7), utf07); assertEquals(rs.getString(8), utf08); rs.close(); PreparedStatement prep = conn.prepareStatement("select ?,?,?,?,?,?,?,?;"); prep.setString(1, utf01); prep.setString(2, utf02); prep.setString(3, utf03); prep.setString(4, utf04); prep.setString(5, utf05); prep.setString(6, utf06); prep.setString(7, utf07); prep.setString(8, utf08); rs = prep.executeQuery(); assertTrue(rs.next()); assertArrayEq(rs.getBytes(1), getUtf8Bytes(utf01)); assertArrayEq(rs.getBytes(2), getUtf8Bytes(utf02)); assertArrayEq(rs.getBytes(3), getUtf8Bytes(utf03)); assertArrayEq(rs.getBytes(4), getUtf8Bytes(utf04)); assertArrayEq(rs.getBytes(5), getUtf8Bytes(utf05)); assertArrayEq(rs.getBytes(6), getUtf8Bytes(utf06)); assertArrayEq(rs.getBytes(7), getUtf8Bytes(utf07)); assertArrayEq(rs.getBytes(8), getUtf8Bytes(utf08)); assertEquals(rs.getString(1), utf01); assertEquals(rs.getString(2), utf02); assertEquals(rs.getString(3), utf03); assertEquals(rs.getString(4), utf04); assertEquals(rs.getString(5), utf05); assertEquals(rs.getString(6), utf06); assertEquals(rs.getString(7), utf07); assertEquals(rs.getString(8), utf08); rs.close(); } @Test public void batch() throws SQLException { ResultSet rs; stat.executeUpdate("create table test (c1, c2, c3, c4);"); PreparedStatement prep = conn.prepareStatement("insert into test values (?,?,?,?);"); for (int i = 0; i < 10; i++) { prep.setInt(1, Integer.MIN_VALUE + i); prep.setFloat(2, Float.MIN_VALUE + i); prep.setString(3, "Hello " + i); prep.setDouble(4, Double.MAX_VALUE + i); prep.addBatch(); } assertArrayEq(prep.executeBatch(), new int[] {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}); prep.close(); rs = stat.executeQuery("select * from test;"); for (int i = 0; i < 10; i++) { assertTrue(rs.next()); assertEquals(rs.getInt(1), Integer.MIN_VALUE + i); assertEquals(rs.getFloat(2), Float.MIN_VALUE + i, 0.0001); assertEquals(rs.getString(3), "Hello " + i); assertEquals(rs.getDouble(4), Double.MAX_VALUE + i, 0.0001); } rs.close(); stat.executeUpdate("drop table test;"); } @Test public void testExecuteBatch() throws Exception { stat.executeUpdate("create table t (c text);"); PreparedStatement prep = conn.prepareStatement("insert into t values (?);"); prep.setString(1, "a"); prep.addBatch(); int call1_length = prep.executeBatch().length; prep.setString(1, "b"); prep.addBatch(); int call2_length = prep.executeBatch().length; assertEquals(1, call1_length); assertEquals(1, call2_length); ResultSet rs = stat.executeQuery("select * from t"); rs.next(); assertEquals("a", rs.getString(1)); rs.next(); assertEquals("b", rs.getString(1)); } @Test public void dblock() throws SQLException { stat.executeUpdate("create table test (c1);"); stat.executeUpdate("insert into test values (1);"); conn.prepareStatement("select * from test;").executeQuery().close(); stat.executeUpdate("drop table test;"); } @Test public void dbclose() throws SQLException { conn.prepareStatement("select ?;").setString(1, "Hello World"); conn.prepareStatement("select null;").close(); conn.prepareStatement("select null;").executeQuery().close(); conn.prepareStatement("create table t (c);").executeUpdate(); conn.prepareStatement("select null;"); } @Test public void batchOneParam() throws SQLException { stat.executeUpdate("create table test (c1);"); PreparedStatement prep = conn.prepareStatement("insert into test values (?);"); for (int i = 0; i < 10; i++) { prep.setInt(1, Integer.MIN_VALUE + i); prep.addBatch(); } assertArrayEq(new int[] {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, prep.executeBatch()); prep.close(); ResultSet rs = stat.executeQuery("select count(*) from test;"); assertTrue(rs.next()); assertEquals(rs.getInt(1), 10); rs.close(); } @Test public void batchZeroParams() throws Exception { stat.executeUpdate("create table test (c1);"); PreparedStatement prep = conn.prepareStatement("insert into test values (5);"); for (int i = 0; i < 10; i++) { prep.addBatch(); } assertArrayEq(new int[] {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, prep.executeBatch()); prep.close(); ResultSet rs = stat.executeQuery("select count(*) from test;"); assertTrue(rs.next()); assertEquals(rs.getInt(1), 10); rs.close(); } @Test public void paramMetaData() throws SQLException { PreparedStatement prep = conn.prepareStatement("select ?,?,?,?;"); assertEquals(prep.getParameterMetaData().getParameterCount(), 4); } @Test public void metaData() throws SQLException { PreparedStatement prep = conn.prepareStatement("select ? as col1, ? as col2, ? as delta;"); ResultSetMetaData meta = prep.getMetaData(); assertEquals(meta.getColumnCount(), 3); assertEquals(meta.getColumnName(1), "col1"); assertEquals(meta.getColumnName(2), "col2"); assertEquals(meta.getColumnName(3), "delta"); /*assertEquals(meta.getColumnType(1), Types.INTEGER); assertEquals(meta.getColumnType(2), Types.INTEGER); assertEquals(meta.getColumnType(3), Types.INTEGER);*/ prep.setInt(1, 2); prep.setInt(2, 3); prep.setInt(3, -1); meta = prep.executeQuery().getMetaData(); assertEquals(meta.getColumnCount(), 3); prep.close(); } @Test public void date1() throws SQLException { Date d1 = new Date(987654321); stat.execute("create table t (c1);"); PreparedStatement prep = conn.prepareStatement("insert into t values(?);"); prep.setDate(1, d1); prep.executeUpdate(); ResultSet rs = stat.executeQuery("select c1 from t;"); assertTrue(rs.next()); assertEquals(rs.getLong(1), d1.getTime()); assertTrue(rs.getDate(1).equals(d1)); rs.close(); } @Test public void date2() throws SQLException { Date d1 = new Date(1092941466000L); stat.execute("create table t (c1);"); PreparedStatement prep = conn.prepareStatement("insert into t values (datetime(?/1000, 'unixepoch'));"); prep.setDate(1, d1); prep.executeUpdate(); ResultSet rs = stat.executeQuery("select strftime('%s', c1) * 1000 from t;"); assertTrue(rs.next()); assertEquals(rs.getLong(1), d1.getTime()); assertTrue(rs.getDate(1).equals(d1)); } @Test public void changeSchema() throws SQLException { stat.execute("create table t (c1);"); PreparedStatement prep = conn.prepareStatement("insert into t values (?);"); conn.createStatement().execute("create table t2 (c2);"); prep.setInt(1, 1000); prep.execute(); prep.executeUpdate(); } // @Ignore // @Test // public void multipleStatements() throws SQLException // { // PreparedStatement prep = conn // .prepareStatement("create table person (id integer, name string); insert into // person values(1, 'leo'); insert into person values(2, 'yui');"); // prep.executeUpdate(); // // ResultSet rs = conn.createStatement().executeQuery("select * from person"); // assertTrue(rs.next()); // assertTrue(rs.next()); // } @Test public void reusingSetValues() throws SQLException { PreparedStatement prep = conn.prepareStatement("select ?,?;"); prep.setInt(1, 9); for (int i = 0; i < 10; i++) { prep.setInt(2, i); ResultSet rs = prep.executeQuery(); assertTrue(rs.next()); assertEquals(rs.getInt(1), 9); assertEquals(rs.getInt(2), i); } for (int i = 0; i < 10; i++) { prep.setInt(2, i); ResultSet rs = prep.executeQuery(); assertTrue(rs.next()); assertEquals(rs.getInt(1), 9); assertEquals(rs.getInt(2), i); rs.close(); } prep.close(); } @Test public void clearParameters() throws SQLException { stat.executeUpdate( "create table tbl (colid integer primary key AUTOINCREMENT, col varchar)"); stat.executeUpdate("insert into tbl(col) values (\"foo\")"); stat.executeUpdate("insert into tbl(col) values (?)"); PreparedStatement prep = conn.prepareStatement("select colid from tbl where col = ?"); prep.setString(1, "foo"); ResultSet rs = prep.executeQuery(); prep.clearParameters(); rs.next(); assertEquals(1, rs.getInt(1)); rs.close(); // should not throw prep.execute(); // should not throw PreparedStatement nullPrep = conn.prepareStatement("select colid from tbl where col is null"); rs = nullPrep.executeQuery(); rs.next(); // gets the row with the NULL column assertEquals(2, rs.getInt(1)); rs.close(); nullPrep.close(); } public void preparedStatementShouldNotThrowIfNotAllParamsSet() throws SQLException { PreparedStatement prep = conn.prepareStatement("select ? as col1, ? as col2, ? as col3;"); ResultSetMetaData meta = prep.getMetaData(); // leaves 0 and 1 unbound assertEquals(meta.getColumnCount(), 3); // we only set one 1 param of the expected 3 params prep.setInt(1, 2); prep.executeQuery(); prep.close(); } public void preparedStatementShouldNotThrowIfNotAllParamsSetBatch() throws SQLException { stat.executeUpdate("create table test (c1, c2);"); PreparedStatement prep = conn.prepareStatement("insert into test values (?,?);"); // leaves param 0 unbound prep.setInt(1, 1); prep.addBatch(); } @Test public void noSuchTable() { assertThrows( SQLException.class, () -> conn.prepareStatement("select * from doesnotexist;")); } @Test public void noSuchCol() throws SQLException { assertThrows( SQLException.class, () -> conn.prepareStatement("select notacol from (select 1);")); } @Test public void noSuchColName() throws SQLException { ResultSet rs = conn.prepareStatement("select 1;").executeQuery(); assertTrue(rs.next()); assertThrows(SQLException.class, () -> rs.getInt("noSuchColName")); } @Test public void constraintErrorCodeExecute() throws SQLException { assertEquals( 0, stat.executeUpdate("create table foo (id integer, CONSTRAINT U_ID UNIQUE (id));")); assertEquals(1, stat.executeUpdate("insert into foo values(1);")); // try to insert a row with duplicate id try { PreparedStatement statement = conn.prepareStatement("insert into foo values(?);"); statement.setInt(1, 1); statement.execute(); fail("expected exception"); } catch (SQLException e) { assertEquals(SQLiteErrorCode.SQLITE_CONSTRAINT.code, e.getErrorCode()); } } @Test public void constraintErrorCodeExecuteUpdate() throws SQLException { assertEquals( 0, stat.executeUpdate("create table foo (id integer, CONSTRAINT U_ID UNIQUE (id));")); assertEquals(1, stat.executeUpdate("insert into foo values(1);")); // try to insert a row with duplicate id try { PreparedStatement statement = conn.prepareStatement("insert into foo values(?);"); statement.setInt(1, 1); statement.executeUpdate(); fail("expected exception"); } catch (SQLException e) { assertEquals(SQLiteErrorCode.SQLITE_CONSTRAINT.code, e.getErrorCode()); } } @Test public void constraintExtendedResultCodeExecute() throws SQLException { assertEquals( 0, stat.executeUpdate("create table foo (id integer, CONSTRAINT U_ID UNIQUE (id));")); assertEquals(1, stat.executeUpdate("insert into foo values(1);")); // try to insert a row with duplicate id try { PreparedStatement statement = conn.prepareStatement("insert into foo values(?);"); statement.setInt(1, 1); statement.execute(); fail("expected exception"); } catch (SQLException e) { assertEquals(SQLiteErrorCode.SQLITE_CONSTRAINT.code, e.getErrorCode()); // Extended error code should be preserved in SQLiteException#resultCode assertEquals( SQLiteErrorCode.SQLITE_CONSTRAINT_UNIQUE, ((SQLiteException) e).getResultCode()); } } private void assertArrayEq(byte[] a, byte[] b) { assertNotNull(a); assertNotNull(b); assertEquals(a.length, b.length); for (int i = 0; i < a.length; i++) { assertEquals(a[i], b[i]); } } private void assertArrayEq(int[] a, int[] b) { assertNotNull(a); assertNotNull(b); assertEquals(a.length, b.length); for (int i = 0; i < a.length; i++) { assertEquals(a[i], b[i]); } } }