diff options
4 files changed, 316 insertions, 33 deletions
diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/ColValidatorEvalContext.java b/src/main/java/com/healthmarketscience/jackcess/impl/ColValidatorEvalContext.java index f55aa17..521fe4d 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/ColValidatorEvalContext.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/ColValidatorEvalContext.java @@ -87,7 +87,7 @@ public class ColValidatorEvalContext extends ColEvalContext "Invalid column value '" + val + "'"); throw new InvalidValueException(withErrorContext(msg)); } - return result; + return val; } finally { reset(); } diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/ColumnImpl.java b/src/main/java/com/healthmarketscience/jackcess/impl/ColumnImpl.java index f195b12..be2bf1c 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/ColumnImpl.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/ColumnImpl.java @@ -2017,7 +2017,7 @@ public class ColumnImpl implements Column, Comparable<ColumnImpl> { boolean isThisColumn(Identifier identifier) { return(getTable().isThisTable(identifier) && - identifier.getObjectName().equalsIgnoreCase(getName())); + getName().equalsIgnoreCase(identifier.getObjectName())); } private static String withErrorContext( diff --git a/src/test/java/com/healthmarketscience/jackcess/PropertyExpressionTest.java b/src/test/java/com/healthmarketscience/jackcess/PropertyExpressionTest.java new file mode 100644 index 0000000..5d3fb44 --- /dev/null +++ b/src/test/java/com/healthmarketscience/jackcess/PropertyExpressionTest.java @@ -0,0 +1,283 @@ +/* +Copyright (c) 2018 James Ahlborn + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package com.healthmarketscience.jackcess; + +import java.util.List; + +import junit.framework.TestCase; + +import static com.healthmarketscience.jackcess.Database.*; +import static com.healthmarketscience.jackcess.TestUtil.*; +import static com.healthmarketscience.jackcess.impl.JetFormatTest.*; + +/** + * + * @author James Ahlborn + */ +public class PropertyExpressionTest extends TestCase +{ + + public PropertyExpressionTest(String name) { + super(name); + } + + public void testDefaultValue() throws Exception + { + for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) { + Database db = create(fileFormat); + db.setEvaluateExpressions(true); + + Table t = new TableBuilder("test") + .addColumn(new ColumnBuilder("id", DataType.LONG).setAutoNumber(true)) + .addColumn(new ColumnBuilder("data1", DataType.TEXT) + .putProperty(PropertyMap.DEFAULT_VALUE_PROP, + "=\"FOO \" & \"BAR\"")) + .addColumn(new ColumnBuilder("data2", DataType.LONG) + .putProperty(PropertyMap.DEFAULT_VALUE_PROP, + "37")) + .toTable(db); + + t.addRow(Column.AUTO_NUMBER, null, 13); + t.addRow(Column.AUTO_NUMBER, "blah", null); + + setProp(t, "data1", PropertyMap.DEFAULT_VALUE_PROP, null); + setProp(t, "data2", PropertyMap.DEFAULT_VALUE_PROP, "42"); + + t.addRow(Column.AUTO_NUMBER, null, null); + + List<Row> expectedRows = + createExpectedTable( + createExpectedRow( + "id", 1, + "data1", "FOO BAR", + "data2", 13), + createExpectedRow( + "id", 2, + "data1", "blah", + "data2", 37), + createExpectedRow( + "id", 3, + "data1", null, + "data2", 42)); + + assertTable(expectedRows, t); + + db.close(); + } + } + + public void testCalculatedValue() throws Exception + { + Database db = create(FileFormat.V2016); + db.setEvaluateExpressions(true); + + Table t = new TableBuilder("test") + .addColumn(new ColumnBuilder("id", DataType.LONG).setAutoNumber(true)) + .addColumn(new ColumnBuilder("c1", DataType.LONG) + .setCalculatedInfo("[c2]+[c3]")) + .addColumn(new ColumnBuilder("c2", DataType.LONG) + .setCalculatedInfo("[c3]*5")) + .addColumn(new ColumnBuilder("c3", DataType.LONG) + .setCalculatedInfo("[c4]-6")) + .addColumn(new ColumnBuilder("c4", DataType.LONG)) + .toTable(db); + + t.addRow(Column.AUTO_NUMBER, null, null, null, 16); + + setProp(t, "c1", PropertyMap.EXPRESSION_PROP, "[c4]+2"); + setProp(t, "c2", PropertyMap.EXPRESSION_PROP, "[c1]+[c3]"); + setProp(t, "c3", PropertyMap.EXPRESSION_PROP, "[c1]*7"); + + t.addRow(Column.AUTO_NUMBER, null, null, null, 7); + + List<Row> expectedRows = + createExpectedTable( + createExpectedRow( + "id", 1, + "c1", 60, + "c2", 50, + "c3", 10, + "c4", 16), + createExpectedRow( + "id", 2, + "c1", 9, + "c2", 72, + "c3", 63, + "c4", 7)); + + assertTable(expectedRows, t); + + db.close(); + } + + public void testColumnValidator() throws Exception + { + for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) { + Database db = create(fileFormat); + db.setEvaluateExpressions(true); + + Table t = new TableBuilder("test") + .addColumn(new ColumnBuilder("id", DataType.LONG).setAutoNumber(true)) + .addColumn(new ColumnBuilder("data1", DataType.LONG) + .putProperty(PropertyMap.VALIDATION_RULE_PROP, + ">37")) + .addColumn(new ColumnBuilder("data2", DataType.LONG) + .putProperty(PropertyMap.VALIDATION_RULE_PROP, + "between 7 and 10") + .putProperty(PropertyMap.VALIDATION_TEXT_PROP, + "You failed")) + .toTable(db); + + t.addRow(Column.AUTO_NUMBER, 42, 8); + + try { + t.addRow(Column.AUTO_NUMBER, 42, 20); + fail("InvalidValueException should have been thrown"); + } catch(InvalidValueException ive) { + // success + assertTrue(ive.getMessage().contains("You failed")); + } + + try { + t.addRow(Column.AUTO_NUMBER, 3, 8); + fail("InvalidValueException should have been thrown"); + } catch(InvalidValueException ive) { + // success + assertFalse(ive.getMessage().contains("You failed")); + } + + t.addRow(Column.AUTO_NUMBER, 54, 9); + + setProp(t, "data1", PropertyMap.VALIDATION_RULE_PROP, null); + setProp(t, "data2", PropertyMap.VALIDATION_RULE_PROP, "<100"); + setProp(t, "data2", PropertyMap.VALIDATION_TEXT_PROP, "Too big"); + + try { + t.addRow(Column.AUTO_NUMBER, 42, 200); + fail("InvalidValueException should have been thrown"); + } catch(InvalidValueException ive) { + // success + assertTrue(ive.getMessage().contains("Too big")); + } + + t.addRow(Column.AUTO_NUMBER, 1, 9); + + List<Row> expectedRows = + createExpectedTable( + createExpectedRow( + "id", 1, + "data1", 42, + "data2", 8), + createExpectedRow( + "id", 2, + "data1", 54, + "data2", 9), + createExpectedRow( + "id", 3, + "data1", 1, + "data2", 9)); + + assertTable(expectedRows, t); + + db.close(); + } + } + + public void testRowValidator() throws Exception + { + for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) { + Database db = create(fileFormat); + db.setEvaluateExpressions(true); + + Table t = new TableBuilder("test") + .addColumn(new ColumnBuilder("id", DataType.LONG).setAutoNumber(true)) + .addColumn(new ColumnBuilder("data1", DataType.LONG)) + .addColumn(new ColumnBuilder("data2", DataType.LONG)) + .putProperty(PropertyMap.VALIDATION_RULE_PROP, + "([data1] > 10) and ([data2] < 100)") + .putProperty(PropertyMap.VALIDATION_TEXT_PROP, + "You failed") + .toTable(db); + + t.addRow(Column.AUTO_NUMBER, 42, 8); + + try { + t.addRow(Column.AUTO_NUMBER, 1, 20); + fail("InvalidValueException should have been thrown"); + } catch(InvalidValueException ive) { + // success + assertTrue(ive.getMessage().contains("You failed")); + } + + t.addRow(Column.AUTO_NUMBER, 54, 9); + + setTableProp(t, PropertyMap.VALIDATION_RULE_PROP, "[data2]<100"); + setTableProp(t, PropertyMap.VALIDATION_TEXT_PROP, "Too big"); + + try { + t.addRow(Column.AUTO_NUMBER, 42, 200); + fail("InvalidValueException should have been thrown"); + } catch(InvalidValueException ive) { + // success + assertTrue(ive.getMessage().contains("Too big")); + } + + t.addRow(Column.AUTO_NUMBER, 1, 9); + + List<Row> expectedRows = + createExpectedTable( + createExpectedRow( + "id", 1, + "data1", 42, + "data2", 8), + createExpectedRow( + "id", 2, + "data1", 54, + "data2", 9), + createExpectedRow( + "id", 3, + "data1", 1, + "data2", 9)); + + assertTable(expectedRows, t); + + db.close(); + } + } + + private static void setProp(Table t, String colName, String propName, + String propVal) throws Exception { + PropertyMap props = t.getColumn(colName).getProperties(); + if(propVal != null) { + props.put(propName, propVal); + } else { + props.remove(propName); + } + props.save(); + } + + private static void setTableProp(Table t, String propName, + String propVal) throws Exception { + PropertyMap props = t.getProperties(); + if(propVal != null) { + props.put(propName, propVal); + } else { + props.remove(propName); + } + props.save(); + } +} diff --git a/src/test/java/com/healthmarketscience/jackcess/TestUtil.java b/src/test/java/com/healthmarketscience/jackcess/TestUtil.java index 7033f7a..7680fb3 100644 --- a/src/test/java/com/healthmarketscience/jackcess/TestUtil.java +++ b/src/test/java/com/healthmarketscience/jackcess/TestUtil.java @@ -53,12 +53,12 @@ import org.junit.Assert; * * @author James Ahlborn */ -public class TestUtil +public class TestUtil { public static final TimeZone TEST_TZ = TimeZone.getTimeZone("America/New_York"); - - private static final ThreadLocal<Boolean> _autoSync = + + private static final ThreadLocal<Boolean> _autoSync = new ThreadLocal<Boolean>(); private TestUtil() {} @@ -76,22 +76,22 @@ public class TestUtil return ((autoSync != null) ? autoSync : Database.DEFAULT_AUTO_SYNC); } - public static Database open(FileFormat fileFormat, File file) - throws Exception + public static Database open(FileFormat fileFormat, File file) + throws Exception { return open(fileFormat, file, false); } - public static Database open(FileFormat fileFormat, File file, boolean inMem) - throws Exception + public static Database open(FileFormat fileFormat, File file, boolean inMem) + throws Exception { FileChannel channel = (inMem ? MemFileChannel.newChannel( - file, DatabaseImpl.RW_CHANNEL_MODE) + file, DatabaseImpl.RW_CHANNEL_MODE) : null); final Database db = new DatabaseBuilder(file).setReadOnly(true) .setAutoSync(getTestAutoSync()).setChannel(channel).open(); - Assert.assertEquals("Wrong JetFormat.", - DatabaseImpl.getFileFormatDetails(fileFormat).getFormat(), + Assert.assertEquals("Wrong JetFormat.", + DatabaseImpl.getFileFormatDetails(fileFormat).getFormat(), ((DatabaseImpl)db).getFormat()); Assert.assertEquals("Wrong FileFormat.", fileFormat, db.getFileFormat()); return db; @@ -109,8 +109,8 @@ public class TestUtil return create(fileFormat, false); } - public static Database create(FileFormat fileFormat, boolean keep) - throws Exception + public static Database create(FileFormat fileFormat, boolean keep) + throws Exception { return create(fileFormat, keep, false); } @@ -119,9 +119,9 @@ public class TestUtil return create(fileFormat, false, true); } - private static Database create(FileFormat fileFormat, boolean keep, - boolean inMem) - throws Exception + private static Database create(FileFormat fileFormat, boolean keep, + boolean inMem) + throws Exception { FileChannel channel = (inMem ? MemFileChannel.newChannel() : null); @@ -147,7 +147,7 @@ public class TestUtil ByteUtil.closeQuietly(outStream); } } - + return new DatabaseBuilder(createTempFile(keep)).setFileFormat(fileFormat) .setAutoSync(getTestAutoSync()).setChannel(channel).create(); } @@ -176,7 +176,7 @@ public class TestUtil File tmp = createTempFile(keep); copyFile(file, tmp); Database db = new DatabaseBuilder(tmp).setAutoSync(getTestAutoSync()).open(); - Assert.assertEquals("Wrong JetFormat.", + Assert.assertEquals("Wrong JetFormat.", DatabaseImpl.getFileFormatDetails(fileFormat).getFormat(), ((DatabaseImpl)db).getFormat()); Assert.assertEquals("Wrong FileFormat.", fileFormat, db.getFileFormat()); @@ -192,7 +192,7 @@ public class TestUtil public 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, @@ -220,7 +220,7 @@ public class TestUtil static String createNonAsciiString(int len) { return createString(len, '\u0CC0'); } - + private static String createString(int len, char firstChar) { StringBuilder builder = new StringBuilder(len); for(int i = 0; i < len; ++i) { @@ -235,7 +235,7 @@ public class TestUtil Assert.assertEquals(expectedRowCount, countRows(table)); Assert.assertEquals(expectedRowCount, table.getRowCount()); } - + public static int countRows(Table table) throws Exception { int rtn = 0; for(Map<String, Object> row : CursorBuilder.createCursor(table)) { @@ -245,15 +245,15 @@ public class TestUtil } public static void assertTable( - List<? extends Map<String, Object>> expectedTable, + 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, + List<? extends Map<String, Object>> expectedTable, Cursor cursor) { List<Map<String, Object>> foundTable = @@ -264,9 +264,9 @@ public class TestUtil Assert.assertEquals(expectedTable.size(), foundTable.size()); for(int i = 0; i < expectedTable.size(); ++i) { Assert.assertEquals(expectedTable.get(i), foundTable.get(i)); - } + } } - + public static RowImpl createExpectedRow(Object... rowElements) { RowImpl row = new RowImpl((RowIdImpl)null); for(int i = 0; i < rowElements.length; i += 2) { @@ -274,12 +274,12 @@ public class TestUtil rowElements[i + 1]); } return row; - } + } public static List<Row> createExpectedTable(Row... rows) { return Arrays.<Row>asList(rows); - } - + } + public static void dumpDatabase(Database mdb) throws Exception { dumpDatabase(mdb, false); } @@ -313,7 +313,7 @@ public class TestUtil for(Index index : table.getIndexes()) { ((IndexImpl)index).initialize(); } - + writer.println("TABLE: " + table.getName()); List<String> colNames = new ArrayList<String>(); for(Column col : table.getColumns()) { @@ -377,7 +377,7 @@ public class TestUtil "), found " + foundTime + " (" + found + ")"); } } - + static void copyFile(File srcFile, File dstFile) throws IOException { @@ -424,7 +424,7 @@ public class TestUtil val = f.get(val); ((Map<?,?>)val).clear(); } - + public static byte[] toByteArray(File file) throws IOException { |