aboutsummaryrefslogtreecommitdiffstats
path: root/src/test/java/com/healthmarketscience/jackcess/DatabaseTest.java
diff options
context:
space:
mode:
authorJames Ahlborn <jtahlborn@yahoo.com>2013-08-16 02:09:48 +0000
committerJames Ahlborn <jtahlborn@yahoo.com>2013-08-16 02:09:48 +0000
commit417fb06208f50cbf164a1c101ac03c7bae0856d8 (patch)
tree52217c1c09bc71377ca0f422ed43d24d6917a178 /src/test/java/com/healthmarketscience/jackcess/DatabaseTest.java
parent790b943d773fc72a11089b6acaf17aa341f92ae4 (diff)
downloadjackcess-417fb06208f50cbf164a1c101ac03c7bae0856d8.tar.gz
jackcess-417fb06208f50cbf164a1c101ac03c7bae0856d8.zip
move files into standard maven dir structure
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@781 f203690c-595d-4dc9-a70b-905162fa7fd2
Diffstat (limited to 'src/test/java/com/healthmarketscience/jackcess/DatabaseTest.java')
-rw-r--r--src/test/java/com/healthmarketscience/jackcess/DatabaseTest.java1686
1 files changed, 1686 insertions, 0 deletions
diff --git a/src/test/java/com/healthmarketscience/jackcess/DatabaseTest.java b/src/test/java/com/healthmarketscience/jackcess/DatabaseTest.java
new file mode 100644
index 0000000..bc5416a
--- /dev/null
+++ b/src/test/java/com/healthmarketscience/jackcess/DatabaseTest.java
@@ -0,0 +1,1686 @@
+/*
+Copyright (c) 2007 Health Market Science, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+USA
+
+You can contact Health Market Science at info@healthmarketscience.com
+or at the following address:
+
+Health Market Science
+2700 Horizon Drive
+Suite 200
+King of Prussia, PA 19406
+*/
+
+package com.healthmarketscience.jackcess;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.math.BigDecimal;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.sql.Types;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TimeZone;
+import java.util.TreeSet;
+import java.util.UUID;
+
+import static com.healthmarketscience.jackcess.Database.*;
+import com.healthmarketscience.jackcess.complex.ComplexValueForeignKey;
+import com.healthmarketscience.jackcess.impl.ByteUtil;
+import com.healthmarketscience.jackcess.impl.ColumnImpl;
+import com.healthmarketscience.jackcess.impl.DatabaseImpl;
+import com.healthmarketscience.jackcess.impl.IndexData;
+import com.healthmarketscience.jackcess.impl.IndexImpl;
+import com.healthmarketscience.jackcess.impl.JetFormat;
+import static com.healthmarketscience.jackcess.impl.JetFormatTest.*;
+import com.healthmarketscience.jackcess.impl.RowIdImpl;
+import com.healthmarketscience.jackcess.impl.RowImpl;
+import com.healthmarketscience.jackcess.impl.TableImpl;
+import com.healthmarketscience.jackcess.util.LinkResolver;
+import com.healthmarketscience.jackcess.util.MemFileChannel;
+import com.healthmarketscience.jackcess.util.RowFilterTest;
+import junit.framework.TestCase;
+
+
+/**
+ * @author Tim McCune
+ */
+public class DatabaseTest extends TestCase {
+
+ public static final TimeZone TEST_TZ =
+ TimeZone.getTimeZone("America/New_York");
+
+ static boolean _autoSync = Database.DEFAULT_AUTO_SYNC;
+
+
+ public DatabaseTest(String name) throws Exception {
+ super(name);
+ }
+
+ public static Database open(FileFormat fileFormat, File file)
+ throws Exception
+ {
+ return open(fileFormat, file, false);
+ }
+
+ private static Database open(FileFormat fileFormat, File file,
+ boolean inMem)
+ throws Exception
+ {
+ FileChannel channel = (inMem ? MemFileChannel.newChannel(file, "r")
+ : null);
+ final Database db = new DatabaseBuilder(file).setReadOnly(true)
+ .setAutoSync(_autoSync).setChannel(channel).open();
+ assertEquals("Wrong JetFormat.",
+ DatabaseImpl.getFileFormatDetails(fileFormat).getFormat(),
+ ((DatabaseImpl)db).getFormat());
+ assertEquals("Wrong FileFormat.", fileFormat, db.getFileFormat());
+ return db;
+ }
+
+ public static Database open(TestDB testDB) throws Exception {
+ return open(testDB.getExpectedFileFormat(), testDB.getFile());
+ }
+
+ public static Database openMem(TestDB testDB) throws Exception {
+ return open(testDB.getExpectedFileFormat(), testDB.getFile(), true);
+ }
+
+ public static Database create(FileFormat fileFormat) throws Exception {
+ return create(fileFormat, false);
+ }
+
+ public static Database create(FileFormat fileFormat, boolean keep)
+ throws Exception
+ {
+ return create(fileFormat, keep, false);
+ }
+
+ public static Database createMem(FileFormat fileFormat) throws Exception {
+ return create(fileFormat, false, true);
+ }
+
+ private static Database create(FileFormat fileFormat, boolean keep,
+ boolean inMem)
+ throws Exception
+ {
+ FileChannel channel = (inMem ? MemFileChannel.newChannel() : null);
+ return new DatabaseBuilder(createTempFile(keep)).setFileFormat(fileFormat)
+ .setAutoSync(_autoSync).setChannel(channel).create();
+ }
+
+
+ public static Database openCopy(TestDB testDB) throws Exception {
+ return openCopy(testDB, false);
+ }
+
+ public static Database openCopy(TestDB testDB, boolean keep)
+ throws Exception
+ {
+ return openCopy(testDB.getExpectedFileFormat(), testDB.getFile(), keep);
+ }
+
+ public static Database openCopy(FileFormat fileFormat, File file)
+ throws Exception
+ {
+ return openCopy(fileFormat, file, false);
+ }
+
+ public static Database openCopy(FileFormat fileFormat, File file,
+ boolean keep)
+ throws Exception
+ {
+ File tmp = createTempFile(keep);
+ copyFile(file, tmp);
+ Database db = new DatabaseBuilder(tmp).setAutoSync(_autoSync).open();
+ assertEquals("Wrong JetFormat.",
+ DatabaseImpl.getFileFormatDetails(fileFormat).getFormat(),
+ ((DatabaseImpl)db).getFormat());
+ assertEquals("Wrong FileFormat.", fileFormat, db.getFileFormat());
+ return db;
+ }
+
+
+ public void testInvalidTableDefs() throws Exception {
+ for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
+ Database db = create(fileFormat);
+
+ try {
+ ((DatabaseImpl)db).createTable("test", Collections.<ColumnBuilder>emptyList());
+ fail("created table with no columns?");
+ } catch(IllegalArgumentException e) {
+ // success
+ }
+
+ try {
+ new TableBuilder("test")
+ .addColumn(new ColumnBuilder("A", DataType.TEXT))
+ .addColumn(new ColumnBuilder("a", DataType.MEMO))
+ .toTable(db);
+ fail("created table with duplicate column names?");
+ } catch(IllegalArgumentException e) {
+ // success
+ }
+
+ try {
+ new TableBuilder("test")
+ .addColumn(new ColumnBuilder("A", DataType.TEXT)
+ .setLengthInUnits(352))
+ .toTable(db);
+ fail("created table with invalid column length?");
+ } catch(IllegalArgumentException e) {
+ // success
+ }
+
+ try {
+ new TableBuilder("test")
+ .addColumn(new ColumnBuilder("A_" + createString(70), DataType.TEXT))
+ .toTable(db);
+ fail("created table with too long column name?");
+ } catch(IllegalArgumentException e) {
+ // success
+ }
+
+ new TableBuilder("test")
+ .addColumn(new ColumnBuilder("A", DataType.TEXT))
+ .toTable(db);
+
+
+ try {
+ new TableBuilder("Test")
+ .addColumn(new ColumnBuilder("A", DataType.TEXT))
+ .toTable(db);
+ fail("create duplicate tables?");
+ } catch(IllegalArgumentException e) {
+ // success
+ }
+
+ db.close();
+ }
+ }
+
+ public void testReadDeletedRows() throws Exception {
+ for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.DEL, true)) {
+ Table table = open(testDB).getTable("Table");
+ int rows = 0;
+ while (table.getNextRow() != null) {
+ rows++;
+ }
+ assertEquals(2, rows);
+ table.getDatabase().close();
+ }
+ }
+
+ public void testGetColumns() throws Exception {
+ for (final TestDB testDB : SUPPORTED_DBS_TEST_FOR_READ) {
+
+ List<? extends Column> columns = open(testDB).getTable("Table1").getColumns();
+ assertEquals(9, columns.size());
+ checkColumn(columns, 0, "A", DataType.TEXT);
+ checkColumn(columns, 1, "B", DataType.TEXT);
+ checkColumn(columns, 2, "C", DataType.BYTE);
+ checkColumn(columns, 3, "D", DataType.INT);
+ checkColumn(columns, 4, "E", DataType.LONG);
+ checkColumn(columns, 5, "F", DataType.DOUBLE);
+ checkColumn(columns, 6, "G", DataType.SHORT_DATE_TIME);
+ checkColumn(columns, 7, "H", DataType.MONEY);
+ checkColumn(columns, 8, "I", DataType.BOOLEAN);
+ }
+ }
+
+ static void checkColumn(List<? extends Column> columns, int columnNumber,
+ String name, DataType dataType)
+ throws Exception
+ {
+ Column column = columns.get(columnNumber);
+ assertEquals(name, column.getName());
+ assertEquals(dataType, column.getType());
+ }
+
+ public void testGetNextRow() throws Exception {
+ for (final TestDB testDB : SUPPORTED_DBS_TEST_FOR_READ) {
+ final Database db = open(testDB);
+ assertEquals(4, db.getTableNames().size());
+ final Table table = db.getTable("Table1");
+
+ Map<String, Object> row1 = table.getNextRow();
+ Map<String, Object> row2 = table.getNextRow();
+
+ if(!"abcdefg".equals(row1.get("A"))) {
+ Map<String, Object> tmpRow = row1;
+ row1 = row2;
+ row2 = tmpRow;
+ }
+
+ checkTestDBTable1RowABCDEFG(testDB, table, row1);
+ checkTestDBTable1RowA(testDB, table, row2);
+
+ db.close();
+ }
+ }
+
+ static void checkTestDBTable1RowABCDEFG(final TestDB testDB, final Table table, final Map<String, Object> row)
+ throws IOException {
+ assertEquals("testDB: " + testDB + "; table: " + table, "abcdefg", row.get("A"));
+ assertEquals("hijklmnop", row.get("B"));
+ assertEquals(new Byte((byte) 2), row.get("C"));
+ assertEquals(new Short((short) 222), row.get("D"));
+ assertEquals(new Integer(333333333), row.get("E"));
+ assertEquals(new Double(444.555d), row.get("F"));
+ final Calendar cal = Calendar.getInstance();
+ cal.setTime((Date) row.get("G"));
+ assertEquals(Calendar.SEPTEMBER, cal.get(Calendar.MONTH));
+ assertEquals(21, cal.get(Calendar.DAY_OF_MONTH));
+ assertEquals(1974, cal.get(Calendar.YEAR));
+ assertEquals(0, cal.get(Calendar.HOUR_OF_DAY));
+ assertEquals(0, cal.get(Calendar.MINUTE));
+ assertEquals(0, cal.get(Calendar.SECOND));
+ assertEquals(0, cal.get(Calendar.MILLISECOND));
+ assertEquals(Boolean.TRUE, row.get("I"));
+ }
+
+ static void checkTestDBTable1RowA(final TestDB testDB, final Table table, final Map<String, Object> row)
+ throws IOException {
+ assertEquals("testDB: " + testDB + "; table: " + table, "a", row.get("A"));
+ assertEquals("b", row.get("B"));
+ assertEquals(new Byte((byte) 0), row.get("C"));
+ assertEquals(new Short((short) 0), row.get("D"));
+ assertEquals(new Integer(0), row.get("E"));
+ assertEquals(new Double(0d), row.get("F"));
+ final Calendar cal = Calendar.getInstance();
+ cal.setTime((Date) row.get("G"));
+ assertEquals(Calendar.DECEMBER, cal.get(Calendar.MONTH));
+ assertEquals(12, cal.get(Calendar.DAY_OF_MONTH));
+ assertEquals(1981, cal.get(Calendar.YEAR));
+ assertEquals(0, cal.get(Calendar.HOUR_OF_DAY));
+ assertEquals(0, cal.get(Calendar.MINUTE));
+ assertEquals(0, cal.get(Calendar.SECOND));
+ assertEquals(0, cal.get(Calendar.MILLISECOND));
+ assertEquals(Boolean.FALSE, row.get("I"));
+ }
+
+ public void testCreate() throws Exception {
+ for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
+ Database db = create(fileFormat);
+ assertEquals(0, db.getTableNames().size());
+ db.close();
+ }
+ }
+
+ public void testWriteAndRead() throws Exception {
+ for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
+ Database db = create(fileFormat);
+ doTestWriteAndRead(db);
+ db.close();
+ }
+ }
+
+ public void testWriteAndReadInMem() throws Exception {
+ for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
+ Database db = createMem(fileFormat);
+ doTestWriteAndRead(db);
+ db.close();
+ }
+ }
+
+ private static void doTestWriteAndRead(Database db) throws Exception {
+ createTestTable(db);
+ Object[] row = createTestRow();
+ row[3] = null;
+ Table table = db.getTable("Test");
+ int count = 1000;
+ for (int i = 0; i < count; i++) {
+ table.addRow(row);
+ }
+ for (int i = 0; i < count; i++) {
+ Map<String, Object> readRow = table.getNextRow();
+ assertEquals(row[0], readRow.get("A"));
+ assertEquals(row[1], readRow.get("B"));
+ assertEquals(row[2], readRow.get("C"));
+ assertEquals(row[3], readRow.get("D"));
+ assertEquals(row[4], readRow.get("E"));
+ assertEquals(row[5], readRow.get("F"));
+ assertEquals(row[6], readRow.get("G"));
+ assertEquals(row[7], readRow.get("H"));
+ }
+ }
+
+ public void testWriteAndReadInBatch() throws Exception {
+ for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
+ Database db = create(fileFormat);
+ createTestTable(db);
+ int count = 1000;
+ List<Object[]> rows = new ArrayList<Object[]>(count);
+ Object[] row = createTestRow();
+ for (int i = 0; i < count; i++) {
+ rows.add(row);
+ }
+ Table table = db.getTable("Test");
+ table.addRows(rows);
+ for (int i = 0; i < count; i++) {
+ Map<String, Object> readRow = table.getNextRow();
+ assertEquals(row[0], readRow.get("A"));
+ assertEquals(row[1], readRow.get("B"));
+ assertEquals(row[2], readRow.get("C"));
+ assertEquals(row[3], readRow.get("D"));
+ assertEquals(row[4], readRow.get("E"));
+ assertEquals(row[5], readRow.get("F"));
+ assertEquals(row[6], readRow.get("G"));
+ assertEquals(row[7], readRow.get("H"));
+ }
+
+ db.close();
+ }
+ }
+
+ public void testDeleteCurrentRow() throws Exception {
+
+ // make sure correct row is deleted
+ for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
+ Database db = create(fileFormat);
+ createTestTable(db);
+ Map<String,Object> row1 = createTestRowMap("Tim1");
+ Map<String,Object> row2 = createTestRowMap("Tim2");
+ Map<String,Object> row3 = createTestRowMap("Tim3");
+ Table table = db.getTable("Test");
+ @SuppressWarnings("unchecked")
+ List<Map<String,Object>> rows = Arrays.asList(row1, row2, row3);
+ table.addRowsFromMaps(rows);
+ assertRowCount(3, table);
+
+ table.reset();
+ table.getNextRow();
+ table.getNextRow();
+ table.getDefaultCursor().deleteCurrentRow();
+
+ table.reset();
+
+ Map<String, Object> outRow = table.getNextRow();
+ assertEquals("Tim1", outRow.get("A"));
+ outRow = table.getNextRow();
+ assertEquals("Tim3", outRow.get("A"));
+ assertRowCount(2, table);
+
+ // test multi row delete/add
+ db = create(fileFormat);
+ createTestTable(db);
+ Object[] row = createTestRow();
+ table = db.getTable("Test");
+ for (int i = 0; i < 10; i++) {
+ row[3] = i;
+ table.addRow(row);
+ }
+ row[3] = 1974;
+ assertRowCount(10, table);
+ table.reset();
+ table.getNextRow();
+ table.getDefaultCursor().deleteCurrentRow();
+ assertRowCount(9, table);
+ table.reset();
+ table.getNextRow();
+ table.getDefaultCursor().deleteCurrentRow();
+ assertRowCount(8, table);
+ table.reset();
+ for (int i = 0; i < 8; i++) {
+ table.getNextRow();
+ }
+ table.getDefaultCursor().deleteCurrentRow();
+ assertRowCount(7, table);
+ table.addRow(row);
+ assertRowCount(8, table);
+ table.reset();
+ for (int i = 0; i < 3; i++) {
+ table.getNextRow();
+ }
+ table.getDefaultCursor().deleteCurrentRow();
+ assertRowCount(7, table);
+ table.reset();
+ assertEquals(2, table.getNextRow().get("D"));
+
+ db.close();
+ }
+ }
+
+ public void testDeleteRow() throws Exception {
+
+ // make sure correct row is deleted
+ for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
+ Database db = create(fileFormat);
+ createTestTable(db);
+ Table table = db.getTable("Test");
+ for(int i = 0; i < 10; ++i) {
+ table.addRowFromMap(createTestRowMap("Tim" + i));
+ }
+ assertRowCount(10, table);
+
+ table.reset();
+
+ List<Row> rows = RowFilterTest.toList(table);
+
+ Row r1 = rows.remove(7);
+ Row r2 = rows.remove(3);
+ assertEquals(8, rows.size());
+
+ assertSame(r2, table.deleteRow(r2));
+ assertSame(r1, table.deleteRow(r1));
+
+ assertTable(rows, table);
+
+ table.deleteRow(r2);
+ table.deleteRow(r1);
+
+ assertTable(rows, table);
+ }
+ }
+
+ public void testReadLongValue() throws Exception {
+
+ for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.TEST2, true)) {
+ Database db = open(testDB);
+ Table table = db.getTable("MSP_PROJECTS");
+ Map<String, Object> row = table.getNextRow();
+ assertEquals("Jon Iles this is a a vawesrasoih aksdkl fas dlkjflkasjd flkjaslkdjflkajlksj dfl lkasjdf lkjaskldfj lkas dlk lkjsjdfkl; aslkdf lkasjkldjf lka skldf lka sdkjfl;kasjd falksjdfljaslkdjf laskjdfk jalskjd flkj aslkdjflkjkjasljdflkjas jf;lkasjd fjkas dasdf asd fasdf asdf asdmhf lksaiyudfoi jasodfj902384jsdf9 aw90se fisajldkfj lkasj dlkfslkd jflksjadf as", row.get("PROJ_PROP_AUTHOR"));
+ assertEquals("T", row.get("PROJ_PROP_COMPANY"));
+ assertEquals("Standard", row.get("PROJ_INFO_CAL_NAME"));
+ assertEquals("Project1", row.get("PROJ_PROP_TITLE"));
+ byte[] foundBinaryData = (byte[])row.get("RESERVED_BINARY_DATA");
+ byte[] expectedBinaryData =
+ toByteArray(new File("src/test/data/test2BinData.dat"));
+ assertTrue(Arrays.equals(expectedBinaryData, foundBinaryData));
+
+ db.close();
+ }
+ }
+
+ public void testWriteLongValue() throws Exception {
+
+ for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
+ Database db = create(fileFormat);
+
+ Table table =
+ new TableBuilder("test")
+ .addColumn(new ColumnBuilder("A", DataType.TEXT))
+ .addColumn(new ColumnBuilder("B", DataType.MEMO))
+ .addColumn(new ColumnBuilder("C", DataType.OLE))
+ .toTable(db);
+
+ String testStr = "This is a test";
+ String longMemo = createString(2030);
+ byte[] oleValue = toByteArray(new File("src/test/data/test2BinData.dat"));
+
+
+ table.addRow(testStr, testStr, null);
+ table.addRow(testStr, longMemo, oleValue);
+
+ table.reset();
+
+ Map<String, Object> row = table.getNextRow();
+
+ assertEquals(testStr, row.get("A"));
+ assertEquals(testStr, row.get("B"));
+ assertNull(row.get("C"));
+
+ row = table.getNextRow();
+
+ assertEquals(testStr, row.get("A"));
+ assertEquals(longMemo, row.get("B"));
+ assertTrue(Arrays.equals(oleValue, (byte[])row.get("C")));
+
+ db.close();
+ }
+ }
+
+ public void testManyMemos() throws Exception {
+ for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
+ Database db = create(fileFormat);
+ final int numColumns = 126;
+ TableBuilder bigTableBuilder = new TableBuilder("test");
+
+ for (int i = 0; i < numColumns; i++)
+ {
+ bigTableBuilder.addColumn(new ColumnBuilder("column_" + i, DataType.MEMO));
+ }
+
+ Table bigTable = bigTableBuilder.toTable(db);
+
+ List<Object[]> expectedRows = new ArrayList<Object[]>();
+
+ for (int j = 0; j < 3; j++)
+ {
+ Object[] rowData = new String[numColumns];
+ for (int i = 0; i < numColumns; i++)
+ {
+ rowData[i] = "v_" + i + ";" + (j + 999);
+ }
+ expectedRows.add(rowData);
+ bigTable.addRow(rowData);
+ }
+
+ String extra1 = createString(100);
+ String extra2 = createString(2050);
+
+ for (int j = 0; j < 1; j++)
+ {
+ Object[] rowData = new String[numColumns];
+ for (int i = 0; i < numColumns; i++)
+ {
+ rowData[i] = "v_" + i + ";" + (j + 999) + extra2;
+ }
+ expectedRows.add(rowData);
+ bigTable.addRow(rowData);
+ }
+
+ for (int j = 0; j < 2; j++)
+ {
+ Object[] rowData = new String[numColumns];
+ for (int i = 0; i < numColumns; i++)
+ {
+ String tmp = "v_" + i + ";" + (j + 999);
+ if((i % 3) == 0) {
+ tmp += extra1;
+ } else if((i % 7) == 0) {
+ tmp += extra2;
+ }
+ rowData[i] = tmp;
+ }
+ expectedRows.add(rowData);
+ bigTable.addRow(rowData);
+ }
+
+ bigTable.reset();
+ Iterator<Object[]> expIter = expectedRows.iterator();
+ for(Map<?,?> row : bigTable) {
+ Object[] expectedRow = expIter.next();
+ assertEquals(Arrays.asList(expectedRow),
+ new ArrayList<Object>(row.values()));
+ }
+
+ db.close();
+ }
+ }
+
+ public void testMissingFile() throws Exception {
+ File bogusFile = new File("fooby-dooby.mdb");
+ assertTrue(!bogusFile.exists());
+ try {
+ new DatabaseBuilder(bogusFile).setReadOnly(true).
+ setAutoSync(_autoSync).open();
+ fail("FileNotFoundException should have been thrown");
+ } catch(FileNotFoundException e) {
+ }
+ assertTrue(!bogusFile.exists());
+ }
+
+ public void testReadWithDeletedCols() throws Exception {
+ for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.DEL_COL, true)) {
+ Table table = open(testDB).getTable("Table1");
+
+ Map<String, Object> expectedRow0 = new LinkedHashMap<String, Object>();
+ expectedRow0.put("id", 0);
+ expectedRow0.put("id2", 2);
+ expectedRow0.put("data", "foo");
+ expectedRow0.put("data2", "foo2");
+
+ Map<String, Object> expectedRow1 = new LinkedHashMap<String, Object>();
+ expectedRow1.put("id", 3);
+ expectedRow1.put("id2", 5);
+ expectedRow1.put("data", "bar");
+ expectedRow1.put("data2", "bar2");
+
+ int rowNum = 0;
+ Map<String, Object> row = null;
+ while ((row = table.getNextRow()) != null) {
+ if(rowNum == 0) {
+ assertEquals(expectedRow0, row);
+ } else if(rowNum == 1) {
+ assertEquals(expectedRow1, row);
+ } else if(rowNum >= 2) {
+ fail("should only have 2 rows");
+ }
+ rowNum++;
+ }
+
+ table.getDatabase().close();
+ }
+ }
+
+ public void testCurrency() throws Exception {
+ for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
+ Database db = create(fileFormat);
+
+ Table table = new TableBuilder("test")
+ .addColumn(new ColumnBuilder("A", DataType.MONEY))
+ .toTable(db);
+
+ table.addRow(new BigDecimal("-2341234.03450"));
+ table.addRow(37L);
+ table.addRow("10000.45");
+
+ table.reset();
+
+ List<Object> foundValues = new ArrayList<Object>();
+ Map<String, Object> row = null;
+ while((row = table.getNextRow()) != null) {
+ foundValues.add(row.get("A"));
+ }
+
+ assertEquals(Arrays.asList(
+ new BigDecimal("-2341234.0345"),
+ new BigDecimal("37.0000"),
+ new BigDecimal("10000.4500")),
+ foundValues);
+
+ try {
+ table.addRow(new BigDecimal("342523234145343543.3453"));
+ fail("IOException should have been thrown");
+ } catch(IOException e) {
+ // ignored
+ }
+
+ db.close();
+ }
+ }
+
+ public void testGUID() throws Exception
+ {
+ for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
+ Database db = create(fileFormat);
+
+ Table table = new TableBuilder("test")
+ .addColumn(new ColumnBuilder("A", DataType.GUID))
+ .toTable(db);
+
+ table.addRow("{32A59F01-AA34-3E29-453F-4523453CD2E6}");
+ table.addRow("{32a59f01-aa34-3e29-453f-4523453cd2e6}");
+ table.addRow("{11111111-1111-1111-1111-111111111111}");
+ table.addRow(" {FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF} ");
+ table.addRow(UUID.fromString("32a59f01-1234-3e29-4aaf-4523453cd2e6"));
+
+ table.reset();
+
+ List<Object> foundValues = new ArrayList<Object>();
+ Map<String, Object> row = null;
+ while((row = table.getNextRow()) != null) {
+ foundValues.add(row.get("A"));
+ }
+
+ assertEquals(Arrays.asList(
+ "{32A59F01-AA34-3E29-453F-4523453CD2E6}",
+ "{32A59F01-AA34-3E29-453F-4523453CD2E6}",
+ "{11111111-1111-1111-1111-111111111111}",
+ "{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}",
+ "{32A59F01-1234-3E29-4AAF-4523453CD2E6}"),
+ foundValues);
+
+ try {
+ table.addRow("3245234");
+ fail("IOException should have been thrown");
+ } catch(IOException e) {
+ // ignored
+ }
+
+ db.close();
+ }
+ }
+
+ public void testNumeric() throws Exception
+ {
+ for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
+ Database db = create(fileFormat);
+
+ ColumnBuilder col = new ColumnBuilder("A", DataType.NUMERIC)
+ .setScale(4).setPrecision(8).toColumn();
+ assertTrue(col.getType().isVariableLength());
+
+ Table table = new TableBuilder("test")
+ .addColumn(col)
+ .addColumn(new ColumnBuilder("B", DataType.NUMERIC)
+ .setScale(8).setPrecision(28))
+ .toTable(db);
+
+ table.addRow(new BigDecimal("-1234.03450"),
+ new BigDecimal("23923434453436.36234219"));
+ table.addRow(37L, 37L);
+ table.addRow("1000.45", "-3452345321000");
+
+ table.reset();
+
+ List<Object> foundSmallValues = new ArrayList<Object>();
+ List<Object> foundBigValues = new ArrayList<Object>();
+ Map<String, Object> row = null;
+ while((row = table.getNextRow()) != null) {
+ foundSmallValues.add(row.get("A"));
+ foundBigValues.add(row.get("B"));
+ }
+
+ assertEquals(Arrays.asList(
+ new BigDecimal("-1234.0345"),
+ new BigDecimal("37.0000"),
+ new BigDecimal("1000.4500")),
+ foundSmallValues);
+ assertEquals(Arrays.asList(
+ new BigDecimal("23923434453436.36234219"),
+ new BigDecimal("37.00000000"),
+ new BigDecimal("-3452345321000.00000000")),
+ foundBigValues);
+
+ try {
+ table.addRow(new BigDecimal("3245234.234"),
+ new BigDecimal("3245234.234"));
+ fail("IOException should have been thrown");
+ } catch(IOException e) {
+ // ignored
+ }
+
+ db.close();
+ }
+ }
+
+ public void testFixedNumeric() throws Exception
+ {
+ for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.FIXED_NUMERIC)) {
+ Database db = openCopy(testDB);
+ Table t = db.getTable("test");
+
+ boolean first = true;
+ for(Column col : t.getColumns()) {
+ if(first) {
+ assertTrue(col.isVariableLength());
+ assertEquals(DataType.MEMO, col.getType());
+ first = false;
+ } else {
+ assertFalse(col.isVariableLength());
+ assertEquals(DataType.NUMERIC, col.getType());
+ }
+ }
+
+ Map<String, Object> row = t.getNextRow();
+ assertEquals("some data", row.get("col1"));
+ assertEquals(new BigDecimal("1"), row.get("col2"));
+ assertEquals(new BigDecimal("0"), row.get("col3"));
+ assertEquals(new BigDecimal("0"), row.get("col4"));
+ assertEquals(new BigDecimal("4"), row.get("col5"));
+ assertEquals(new BigDecimal("-1"), row.get("col6"));
+ assertEquals(new BigDecimal("1"), row.get("col7"));
+
+ Object[] tmpRow = new Object[]{
+ "foo", new BigDecimal("1"), new BigDecimal(3), new BigDecimal("13"),
+ new BigDecimal("-17"), new BigDecimal("0"), new BigDecimal("8734")};
+ t.addRow(tmpRow);
+ t.reset();
+
+ t.getNextRow();
+ row = t.getNextRow();
+ assertEquals(tmpRow[0], row.get("col1"));
+ assertEquals(tmpRow[1], row.get("col2"));
+ assertEquals(tmpRow[2], row.get("col3"));
+ assertEquals(tmpRow[3], row.get("col4"));
+ assertEquals(tmpRow[4], row.get("col5"));
+ assertEquals(tmpRow[5], row.get("col6"));
+ assertEquals(tmpRow[6], row.get("col7"));
+
+ db.close();
+ }
+ }
+
+ public void testMultiPageTableDef() throws Exception
+ {
+ for (final TestDB testDB : SUPPORTED_DBS_TEST_FOR_READ) {
+ List<? extends Column> columns = open(testDB).getTable("Table2").getColumns();
+ assertEquals(89, columns.size());
+ }
+ }
+
+ public void testOverflow() throws Exception
+ {
+ for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.OVERFLOW, true)) {
+ Database mdb = open(testDB);
+ Table table = mdb.getTable("Table1");
+
+ // 7 rows, 3 and 5 are overflow
+ table.getNextRow();
+ table.getNextRow();
+
+ Map<String, Object> row = table.getNextRow();
+ assertEquals(Arrays.<Object>asList(
+ null, "row3col3", null, null, null, null, null,
+ "row3col9", null),
+ new ArrayList<Object>(row.values()));
+
+ table.getNextRow();
+
+ row = table.getNextRow();
+ assertEquals(Arrays.<Object>asList(
+ null, "row5col2", null, null, null, null, null, null,
+ null),
+ new ArrayList<Object>(row.values()));
+
+ table.reset();
+ assertRowCount(7, table);
+
+ mdb.close();
+ }
+ }
+
+ public void testLongValueAsMiddleColumn() throws Exception
+ {
+ for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
+ Database db = create(fileFormat);
+ Table newTable = new TableBuilder("NewTable")
+ .addColumn(new ColumnBuilder("a").setSQLType(Types.INTEGER))
+ .addColumn(new ColumnBuilder("b").setSQLType(Types.LONGVARCHAR))
+ .addColumn(new ColumnBuilder("c").setSQLType(Types.VARCHAR))
+ .toTable(db);
+
+ String lval = createString(2000); // "--2000 chars long text--";
+ String tval = createString(40); // "--40chars long text--";
+ newTable.addRow(new Integer(1), lval, tval);
+
+ newTable = db.getTable("NewTable");
+ Map<String, Object> readRow = newTable.getNextRow();
+ assertEquals(new Integer(1), readRow.get("a"));
+ assertEquals(lval, readRow.get("b"));
+ assertEquals(tval, readRow.get("c"));
+
+ db.close();
+ }
+ }
+
+
+ public void testUsageMapPromotion() throws Exception {
+ for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.PROMOTION)) {
+ Database db = openCopy(testDB);
+ Table t = db.getTable("jobDB1");
+
+ assertTrue(((TableImpl)t).getOwnedPagesCursor().getUsageMap().toString()
+ .startsWith("(InlineHandler)"));
+
+ String lval = createNonAsciiString(255); // "--255 chars long text--";
+
+ for(int i = 0; i < 1000; ++i) {
+ t.addRow(i, 13, 57, lval, lval, lval, lval, lval, lval, 47.0d);
+ }
+
+ Set<Integer> ids = new HashSet<Integer>();
+ for(Map<String,Object> row : t) {
+ ids.add((Integer)row.get("ID"));
+ }
+ assertEquals(1000, ids.size());
+
+ assertTrue(((TableImpl)t).getOwnedPagesCursor().getUsageMap().toString()
+ .startsWith("(ReferenceHandler)"));
+
+ db.close();
+ }
+ }
+
+
+ public void testLargeTableDef() throws Exception {
+ for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
+ Database db = create(fileFormat);
+
+ final int numColumns = 90;
+
+ List<ColumnBuilder> columns = new ArrayList<ColumnBuilder>();
+ List<String> colNames = new ArrayList<String>();
+ for(int i = 0; i < numColumns; ++i) {
+ String colName = "MyColumnName" + i;
+ colNames.add(colName);
+ columns.add(new ColumnBuilder(colName, DataType.TEXT).toColumn());
+ }
+
+ ((DatabaseImpl)db).createTable("test", columns);
+
+ Table t = db.getTable("test");
+
+ List<String> row = new ArrayList<String>();
+ Map<String,Object> expectedRowData = new LinkedHashMap<String, Object>();
+ for(int i = 0; i < numColumns; ++i) {
+ String value = "" + i + " some row data";
+ row.add(value);
+ expectedRowData.put(colNames.get(i), value);
+ }
+
+ t.addRow(row.toArray());
+
+ t.reset();
+ assertEquals(expectedRowData, t.getNextRow());
+
+ db.close();
+ }
+ }
+
+ public void testAutoNumber() throws Exception {
+ for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
+ Database db = create(fileFormat);
+
+ Table table = new TableBuilder("test")
+ .addColumn(new ColumnBuilder("a", DataType.LONG)
+ .setAutoNumber(true))
+ .addColumn(new ColumnBuilder("b", DataType.TEXT))
+ .toTable(db);
+
+ doTestAutoNumber(table);
+
+ db.close();
+ }
+ }
+
+ public void testAutoNumberPK() throws Exception {
+ for (final TestDB testDB : SUPPORTED_DBS_TEST) {
+ Database db = openCopy(testDB);
+
+ Table table = db.getTable("Table3");
+
+ doTestAutoNumber(table);
+
+ db.close();
+ }
+ }
+
+ private void doTestAutoNumber(Table table) throws Exception
+ {
+ Object[] row = {null, "row1"};
+ assertSame(row, table.addRow(row));
+ assertEquals(1, ((Integer)row[0]).intValue());
+ row = table.addRow(13, "row2");
+ assertEquals(2, ((Integer)row[0]).intValue());
+ row = table.addRow("flubber", "row3");
+ assertEquals(3, ((Integer)row[0]).intValue());
+
+ table.reset();
+
+ row = table.addRow(Column.AUTO_NUMBER, "row4");
+ assertEquals(4, ((Integer)row[0]).intValue());
+ row = table.addRow(Column.AUTO_NUMBER, "row5");
+ assertEquals(5, ((Integer)row[0]).intValue());
+
+ Object[] smallRow = {Column.AUTO_NUMBER};
+ row = table.addRow(smallRow);
+ assertNotSame(row, smallRow);
+ assertEquals(6, ((Integer)row[0]).intValue());
+
+ table.reset();
+
+ List<? extends Map<String, Object>> expectedRows =
+ createExpectedTable(
+ createExpectedRow(
+ "a", 1,
+ "b", "row1"),
+ createExpectedRow(
+ "a", 2,
+ "b", "row2"),
+ createExpectedRow(
+ "a", 3,
+ "b", "row3"),
+ createExpectedRow(
+ "a", 4,
+ "b", "row4"),
+ createExpectedRow(
+ "a", 5,
+ "b", "row5"),
+ createExpectedRow(
+ "a", 6,
+ "b", null));
+
+ assertTable(expectedRows, table);
+ }
+
+ public void testWriteAndReadDate() throws Exception {
+ for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
+ Database db = create(fileFormat);
+
+ Table table = new TableBuilder("test")
+ .addColumn(new ColumnBuilder("name", DataType.TEXT))
+ .addColumn(new ColumnBuilder("date", DataType.SHORT_DATE_TIME))
+ .toTable(db);
+
+ // since jackcess does not really store millis, shave them off before
+ // storing the current date/time
+ long curTimeNoMillis = (System.currentTimeMillis() / 1000L);
+ curTimeNoMillis *= 1000L;
+
+ DateFormat df = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
+ List<Date> dates =
+ new ArrayList<Date>(
+ Arrays.asList(
+ df.parse("19801231 00:00:00"),
+ df.parse("19930513 14:43:27"),
+ null,
+ df.parse("20210102 02:37:00"),
+ new Date(curTimeNoMillis)));
+
+ Calendar c = Calendar.getInstance();
+ for(int year = 1801; year < 2050; year +=3) {
+ for(int month = 0; month <= 12; ++month) {
+ for(int day = 1; day < 29; day += 3) {
+ c.clear();
+ c.set(Calendar.YEAR, year);
+ c.set(Calendar.MONTH, month);
+ c.set(Calendar.DAY_OF_MONTH, day);
+ dates.add(c.getTime());
+ }
+ }
+ }
+
+ for(Date d : dates) {
+ table.addRow("row " + d, d);
+ }
+
+ List<Date> foundDates = new ArrayList<Date>();
+ for(Map<String,Object> row : table) {
+ foundDates.add((Date)row.get("date"));
+ }
+
+ assertEquals(dates.size(), foundDates.size());
+ for(int i = 0; i < dates.size(); ++i) {
+ Date expected = dates.get(i);
+ Date found = foundDates.get(i);
+ assertSameDate(expected, found);
+ }
+
+ db.close();
+ }
+ }
+
+ public void testSystemTable() throws Exception
+ {
+ for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
+ Database db = create(fileFormat);
+
+ Set<String> sysTables = new TreeSet<String>(
+ String.CASE_INSENSITIVE_ORDER);
+ sysTables.addAll(
+ Arrays.asList("MSysObjects", "MSysQueries", "MSysACES",
+ "MSysRelationships"));
+
+ if (fileFormat.ordinal() < FileFormat.V2003.ordinal()) {
+ assertNotNull("file format: " + fileFormat, db.getSystemTable("MSysAccessObjects"));
+ sysTables.add("MSysAccessObjects");
+ } else {
+ // v2003+ template files have no "MSysAccessObjects" table
+ assertNull("file format: " + fileFormat, db.getSystemTable("MSysAccessObjects"));
+ sysTables.addAll(
+ Arrays.asList("MSysNavPaneGroupCategories",
+ "MSysNavPaneGroups", "MSysNavPaneGroupToObjects",
+ "MSysNavPaneObjectIDs", "MSysAccessStorage"));
+ if(fileFormat.ordinal() >= FileFormat.V2007.ordinal()) {
+ sysTables.addAll(
+ Arrays.asList(
+ "MSysComplexColumns", "MSysComplexType_Attachment",
+ "MSysComplexType_Decimal", "MSysComplexType_GUID",
+ "MSysComplexType_IEEEDouble", "MSysComplexType_IEEESingle",
+ "MSysComplexType_Long", "MSysComplexType_Short",
+ "MSysComplexType_Text", "MSysComplexType_UnsignedByte"));
+ }
+ if(fileFormat.ordinal() >= FileFormat.V2010.ordinal()) {
+ sysTables.add("f_12D7448B56564D8AAE333BCC9B3718E5_Data");
+ sysTables.add("MSysResources");
+ }
+ }
+
+ assertEquals(sysTables, db.getSystemTableNames());
+
+ assertNotNull(db.getSystemTable("MSysObjects"));
+ assertNotNull(db.getSystemTable("MSysQueries"));
+ assertNotNull(db.getSystemTable("MSysACES"));
+ assertNotNull(db.getSystemTable("MSysRelationships"));
+
+ assertNull(db.getSystemTable("MSysBogus"));
+
+
+ db.close();
+ }
+ }
+
+ public void testUpdateRow() throws Exception
+ {
+ for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
+ Database db = create(fileFormat);
+
+ Table t = new TableBuilder("test")
+ .addColumn(new ColumnBuilder("name", DataType.TEXT))
+ .addColumn(new ColumnBuilder("id", DataType.LONG)
+ .setAutoNumber(true))
+ .addColumn(new ColumnBuilder("data", DataType.TEXT)
+ .setLength(JetFormat.TEXT_FIELD_MAX_LENGTH))
+ .toTable(db);
+
+ for(int i = 0; i < 10; ++i) {
+ t.addRow("row" + i, Column.AUTO_NUMBER, "initial data");
+ }
+
+ Cursor c = CursorBuilder.createCursor(t);
+ c.reset();
+ c.moveNextRows(2);
+ Map<String,Object> row = c.getCurrentRow();
+
+ assertEquals(createExpectedRow("name", "row1",
+ "id", 2,
+ "data", "initial data"),
+ row);
+
+ Map<String,Object> newRow = createExpectedRow(
+ "name", Column.KEEP_VALUE,
+ "id", Column.AUTO_NUMBER,
+ "data", "new data");
+ assertSame(newRow, c.updateCurrentRowFromMap(newRow));
+ assertEquals(createExpectedRow("name", "row1",
+ "id", 2,
+ "data", "new data"),
+ newRow);
+
+ c.moveNextRows(3);
+ row = c.getCurrentRow();
+
+ assertEquals(createExpectedRow("name", "row4",
+ "id", 5,
+ "data", "initial data"),
+ row);
+
+ c.updateCurrentRow(Column.KEEP_VALUE, Column.AUTO_NUMBER, "a larger amount of new data");
+
+ c.reset();
+ c.moveNextRows(2);
+ row = c.getCurrentRow();
+
+ assertEquals(createExpectedRow("name", "row1",
+ "id", 2,
+ "data", "new data"),
+ row);
+
+ c.moveNextRows(3);
+ row = c.getCurrentRow();
+
+ assertEquals(createExpectedRow("name", "row4",
+ "id", 5,
+ "data", "a larger amount of new data"),
+ row);
+
+ t.reset();
+
+ String str = createString(100);
+ for(int i = 10; i < 50; ++i) {
+ t.addRow("row" + i, Column.AUTO_NUMBER, "big data_" + str);
+ }
+
+ c.reset();
+ c.moveNextRows(9);
+ row = c.getCurrentRow();
+
+ assertEquals(createExpectedRow("name", "row8",
+ "id", 9,
+ "data", "initial data"),
+ row);
+
+ String newText = "updated big data_" + createString(200);
+
+ c.setCurrentRowValue(t.getColumn("data"), newText);
+
+ c.reset();
+ c.moveNextRows(9);
+ row = c.getCurrentRow();
+
+ assertEquals(createExpectedRow("name", "row8",
+ "id", 9,
+ "data", newText),
+ row);
+
+ List<Row> rows = RowFilterTest.toList(t);
+ assertEquals(50, rows.size());
+
+ for(Row r : rows) {
+ r.put("data", "final data " + r.get("id"));
+ }
+
+ for(Row r : rows) {
+ assertSame(r, t.updateRow(r));
+ }
+
+ t.reset();
+
+ for(Row r : t) {
+ assertEquals("final data " + r.get("id"), r.get("data"));
+ }
+
+ db.close();
+ }
+ }
+
+ public void testFixedText() throws Exception
+ {
+ for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.FIXED_TEXT)) {
+ Database db = openCopy(testDB);
+
+ Table t = db.getTable("users");
+ Column c = t.getColumn("c_flag_");
+ assertEquals(DataType.TEXT, c.getType());
+ assertEquals(false, c.isVariableLength());
+ assertEquals(2, c.getLength());
+
+ Map<String,Object> row = t.getNextRow();
+ assertEquals("N", row.get("c_flag_"));
+
+ t.addRow(3, "testFixedText", "boo", "foo", "bob", 3, 5, 9, "Y",
+ new Date());
+
+ t.getNextRow();
+ row = t.getNextRow();
+ assertEquals("testFixedText", row.get("c_user_login"));
+ assertEquals("Y", row.get("c_flag_"));
+
+ db.close();
+ }
+ }
+
+ public void testDbSortOrder() throws Exception {
+
+ for (final TestDB testDB : SUPPORTED_DBS_TEST_FOR_READ) {
+
+ Database db = open(testDB);
+ assertEquals(((DatabaseImpl)db).getFormat().DEFAULT_SORT_ORDER,
+ ((DatabaseImpl)db).getDefaultSortOrder());
+ db.close();
+ }
+ }
+
+ public void testUnsupportedColumns() throws Exception {
+ for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.UNSUPPORTED)) {
+
+ Database db = open(testDB);
+ Table t = db.getTable("Test");
+ Column varCol = t.getColumn("UnknownVar");
+ assertEquals(DataType.UNSUPPORTED_VARLEN, varCol.getType());
+ Column fixCol = t.getColumn("UnknownFix");
+ assertEquals(DataType.UNSUPPORTED_FIXEDLEN, fixCol.getType());
+
+ List<String> varVals = Arrays.asList(
+ "RawData: FF FE 73 6F 6D 65 64 61 74 61",
+ "RawData: FF FE 6F 74 68 65 72 20 64 61 74 61",
+ null);
+ List<String> fixVals = Arrays.asList("RawData: 37 00 00 00",
+ "RawData: F3 FF FF FF",
+ "RawData: 02 00 00 00");
+
+ int idx = 0;
+ for(Map<String,Object> row : t) {
+ checkRawValue(varVals.get(idx), varCol.getRowValue(row));
+ checkRawValue(fixVals.get(idx), fixCol.getRowValue(row));
+ ++idx;
+ }
+ db.close();
+ }
+ }
+
+ public void testLinkedTables() throws Exception {
+ for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.LINKED)) {
+ Database db = openCopy(testDB);
+
+ try {
+ db.getTable("Table2");
+ fail("FileNotFoundException should have been thrown");
+ } catch(FileNotFoundException e) {
+ // success
+ }
+
+ assertTrue(db.getLinkedDatabases().isEmpty());
+
+ final String linkeeDbName = "Z:\\jackcess_test\\linkeeTest.accdb";
+ final File linkeeFile = new File("src/test/data/linkeeTest.accdb");
+ db.setLinkResolver(new LinkResolver() {
+ public Database resolveLinkedDatabase(Database linkerdb, String dbName)
+ throws IOException {
+ assertEquals(linkeeDbName, dbName);
+ return DatabaseBuilder.open(linkeeFile);
+ }
+ });
+
+ Table t2 = db.getTable("Table2");
+
+ assertEquals(1, db.getLinkedDatabases().size());
+ Database linkeeDb = db.getLinkedDatabases().get(linkeeDbName);
+ assertNotNull(linkeeDb);
+ assertEquals(linkeeFile, linkeeDb.getFile());
+
+ List<? extends Map<String, Object>> expectedRows =
+ createExpectedTable(
+ createExpectedRow(
+ "ID", 1,
+ "Field1", "bar"));
+
+ assertTable(expectedRows, t2);
+
+ db.createLinkedTable("FooTable", linkeeDbName, "Table2");
+
+ Table t3 = db.getTable("FooTable");
+
+ assertEquals(1, db.getLinkedDatabases().size());
+
+ expectedRows =
+ createExpectedTable(
+ createExpectedRow(
+ "ID", 1,
+ "Field1", "buzz"));
+
+ assertTable(expectedRows, t3);
+
+ db.close();
+ }
+ }
+
+ public void testTimeZone() throws Exception
+ {
+ TimeZone tz = TimeZone.getTimeZone("America/New_York");
+ doTestTimeZone(tz);
+
+ tz = TimeZone.getTimeZone("Australia/Sydney");
+ doTestTimeZone(tz);
+ }
+
+ private static void doTestTimeZone(final TimeZone tz) throws Exception
+ {
+ ColumnImpl col = new ColumnImpl(null, DataType.SHORT_DATE_TIME, 0, 0, 0) {
+ @Override
+ protected Calendar getCalendar() { return Calendar.getInstance(tz); }
+ };
+
+ SimpleDateFormat df = new SimpleDateFormat("yyyy.MM.dd");
+ df.setTimeZone(tz);
+
+ long startDate = df.parse("2012.01.01").getTime();
+ long endDate = df.parse("2013.01.01").getTime();
+
+ Calendar curCal = Calendar.getInstance(tz);
+ curCal.setTimeInMillis(startDate);
+
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
+ sdf.setTimeZone(tz);
+
+ while(curCal.getTimeInMillis() < endDate) {
+ Date curDate = curCal.getTime();
+ Date newDate = new Date(col.fromDateDouble(col.toDateDouble(curDate)));
+ if(curDate.getTime() != newDate.getTime()) {
+ assertEquals(sdf.format(curDate), sdf.format(newDate));
+ }
+ curCal.add(Calendar.MINUTE, 30);
+ }
+ }
+
+ private void checkRawValue(String expected, Object val)
+ {
+ if(expected != null) {
+ assertTrue(ColumnImpl.isRawData(val));
+ assertEquals(expected, val.toString());
+ } else {
+ assertNull(val);
+ }
+ }
+
+ static Object[] createTestRow(String col1Val) {
+ return new Object[] {col1Val, "R", "McCune", 1234, (byte) 0xad, 555.66d,
+ 777.88f, (short) 999, new Date()};
+ }
+
+ static Object[] createTestRow() {
+ return createTestRow("Tim");
+ }
+
+ static Map<String,Object> createTestRowMap(String col1Val) {
+ return createExpectedRow("A", col1Val, "B", "R", "C", "McCune",
+ "D", 1234, "E", (byte) 0xad, "F", 555.66d,
+ "G", 777.88f, "H", (short) 999, "I", new Date());
+ }
+
+ static void createTestTable(Database db) throws Exception {
+ new TableBuilder("test")
+ .addColumn(new ColumnBuilder("A", DataType.TEXT))
+ .addColumn(new ColumnBuilder("B", DataType.TEXT))
+ .addColumn(new ColumnBuilder("C", DataType.TEXT))
+ .addColumn(new ColumnBuilder("D", DataType.LONG))
+ .addColumn(new ColumnBuilder("E", DataType.BYTE))
+ .addColumn(new ColumnBuilder("F", DataType.DOUBLE))
+ .addColumn(new ColumnBuilder("G", DataType.FLOAT))
+ .addColumn(new ColumnBuilder("H", DataType.INT))
+ .addColumn(new ColumnBuilder("I", DataType.SHORT_DATE_TIME))
+ .toTable(db);
+ }
+
+ public static String createString(int len) {
+ return createString(len, 'a');
+ }
+
+ static String createNonAsciiString(int len) {
+ return createString(len, '\u00C0');
+ }
+
+ private static String createString(int len, char firstChar) {
+ StringBuilder builder = new StringBuilder(len);
+ for(int i = 0; i < len; ++i) {
+ builder.append((char)(firstChar + (i % 26)));
+ }
+ return builder.toString();
+ }
+
+ static void assertRowCount(int expectedRowCount, Table table)
+ throws Exception
+ {
+ assertEquals(expectedRowCount, countRows(table));
+ assertEquals(expectedRowCount, table.getRowCount());
+ }
+
+ public static int countRows(Table table) throws Exception {
+ int rtn = 0;
+ for(Map<String, Object> row : CursorBuilder.createCursor(table)) {
+ rtn++;
+ }
+ return rtn;
+ }
+
+ public static void assertTable(
+ List<? extends Map<String, Object>> expectedTable,
+ Table table)
+ throws IOException
+ {
+ assertCursor(expectedTable, CursorBuilder.createCursor(table));
+ }
+
+ public static void assertCursor(
+ List<? extends Map<String, Object>> expectedTable,
+ Cursor cursor)
+ {
+ List<Map<String, Object>> foundTable =
+ new ArrayList<Map<String, Object>>();
+ for(Map<String, Object> row : cursor) {
+ foundTable.add(row);
+ }
+ assertEquals(expectedTable, foundTable);
+ }
+
+ public static RowImpl createExpectedRow(Object... rowElements) {
+ RowImpl row = new RowImpl((RowIdImpl)null);
+ for(int i = 0; i < rowElements.length; i += 2) {
+ row.put((String)rowElements[i],
+ rowElements[i + 1]);
+ }
+ return row;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static List<Row> createExpectedTable(Row... rows) {
+ return Arrays.<Row>asList(rows);
+ }
+
+ static void dumpDatabase(Database mdb) throws Exception {
+ dumpDatabase(mdb, false);
+ }
+
+ static void dumpDatabase(Database mdb, boolean systemTables)
+ throws Exception
+ {
+ dumpDatabase(mdb, systemTables, new PrintWriter(System.out, true));
+ }
+
+ static void dumpTable(Table table) throws Exception {
+ dumpTable(table, new PrintWriter(System.out, true));
+ }
+
+ static void dumpDatabase(Database mdb, boolean systemTables,
+ PrintWriter writer) throws Exception
+ {
+ writer.println("DATABASE:");
+ for(Table table : mdb) {
+ dumpTable(table, writer);
+ }
+ if(systemTables) {
+ for(String sysTableName : mdb.getSystemTableNames()) {
+ dumpTable(mdb.getSystemTable(sysTableName), writer);
+ }
+ }
+ }
+
+ static void dumpTable(Table table, PrintWriter writer) throws Exception {
+ // make sure all indexes are read
+ for(Index index : table.getIndexes()) {
+ ((IndexImpl)index).initialize();
+ }
+
+ writer.println("TABLE: " + table.getName());
+ List<String> colNames = new ArrayList<String>();
+ for(Column col : table.getColumns()) {
+ colNames.add(col.getName());
+ }
+ writer.println("COLUMNS: " + colNames);
+ for(Map<String, Object> row : CursorBuilder.createCursor(table)) {
+ writer.println(massageRow(row));
+ }
+ }
+
+ private static Map<String,Object> massageRow(Map<String, Object> row)
+ throws IOException
+ {
+ for(Map.Entry<String, Object> entry : row.entrySet()) {
+ Object v = entry.getValue();
+ if(v instanceof byte[]) {
+ // make byte[] printable
+ byte[] bv = (byte[])v;
+ entry.setValue(ByteUtil.toHexString(ByteBuffer.wrap(bv), bv.length));
+ } else if(v instanceof ComplexValueForeignKey) {
+ // deref complex values
+ String str = "ComplexValue(" + v + ")" +
+ ((ComplexValueForeignKey)v).getValues();
+ entry.setValue(str);
+ }
+ }
+
+ return row;
+ }
+
+ static void dumpIndex(Index index) throws Exception {
+ dumpIndex(index, new PrintWriter(System.out, true));
+ }
+
+ static void dumpIndex(Index index, PrintWriter writer) throws Exception {
+ writer.println("INDEX: " + index);
+ IndexData.EntryCursor ec = ((IndexImpl)index).cursor();
+ IndexData.Entry lastE = ec.getLastEntry();
+ IndexData.Entry e = null;
+ while((e = ec.getNextEntry()) != lastE) {
+ writer.println(e);
+ }
+ }
+
+ static void assertSameDate(Date expected, Date found)
+ {
+ if(expected == found) {
+ return;
+ }
+ if((expected == null) || (found == null)) {
+ throw new AssertionError("Expected " + expected + ", found " + found);
+ }
+ long expTime = expected.getTime();
+ long foundTime = found.getTime();
+ // there are some rounding issues due to dates being stored as doubles,
+ // but it results in a 1 millisecond difference, so i'm not going to worry
+ // about it
+ if((expTime != foundTime) && (Math.abs(expTime - foundTime) > 1)) {
+ throw new AssertionError("Expected " + expTime + " (" + expected +
+ "), found " + foundTime + " (" + found + ")");
+ }
+ }
+
+ static void copyFile(File srcFile, File dstFile)
+ throws IOException
+ {
+ // FIXME should really be using commons io FileUtils here, but don't want
+ // to add dep for one simple test method
+ byte[] buf = new byte[1024];
+ OutputStream ostream = new FileOutputStream(dstFile);
+ InputStream istream = new FileInputStream(srcFile);
+ try {
+ int numBytes = 0;
+ while((numBytes = istream.read(buf)) >= 0) {
+ ostream.write(buf, 0, numBytes);
+ }
+ } finally {
+ ostream.close();
+ }
+ }
+
+ static File createTempFile(boolean keep) throws Exception {
+ File tmp = File.createTempFile("databaseTest", ".mdb");
+ if(keep) {
+ System.out.println("Created " + tmp);
+ } else {
+ tmp.deleteOnExit();
+ }
+ return tmp;
+ }
+
+ public static byte[] toByteArray(File file)
+ throws IOException
+ {
+ // FIXME should really be using commons io IOUtils here, but don't want
+ // to add dep for one simple test method
+ FileInputStream istream = new FileInputStream(file);
+ try {
+ byte[] bytes = new byte[(int)file.length()];
+ istream.read(bytes);
+ return bytes;
+ } finally {
+ istream.close();
+ }
+ }
+
+}