/*
* Copyright (c) 2009, SQL Power Group Inc.
*
* This file is part of SQL Power Library.
*
* SQL Power Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* SQL Power 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package ca.sqlpower.testutil;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.math.BigDecimal;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import ca.sqlpower.object.SPObject;
import ca.sqlpower.query.SQLGroupFunction;
import ca.sqlpower.sql.DataSourceCollection;
import ca.sqlpower.sql.JDBCDataSource;
import ca.sqlpower.sql.Olap4jDataSource;
import ca.sqlpower.sql.PlDotIni;
import ca.sqlpower.sql.SPDataSource;
import ca.sqlpower.sqlobject.SQLCatalog;
import ca.sqlpower.sqlobject.SQLCheckConstraint;
import ca.sqlpower.sqlobject.SQLCheckConstraintContainer;
import ca.sqlpower.sqlobject.SQLColumn;
import ca.sqlpower.sqlobject.SQLDatabase;
import ca.sqlpower.sqlobject.SQLEnumeration;
import ca.sqlpower.sqlobject.SQLIndex;
import ca.sqlpower.sqlobject.SQLIndex.AscendDescend;
import ca.sqlpower.sqlobject.SQLIndex.Column;
import ca.sqlpower.sqlobject.SQLObject;
import ca.sqlpower.sqlobject.SQLObjectException;
import ca.sqlpower.sqlobject.SQLObjectRoot;
import ca.sqlpower.sqlobject.SQLObjectRuntimeException;
import ca.sqlpower.sqlobject.SQLRelationship;
import ca.sqlpower.sqlobject.SQLRelationship.ColumnMapping;
import ca.sqlpower.sqlobject.SQLRelationship.Deferrability;
import ca.sqlpower.sqlobject.SQLRelationship.SQLImportedKey;
import ca.sqlpower.sqlobject.SQLRelationship.UpdateDeleteRule;
import ca.sqlpower.sqlobject.SQLSchema;
import ca.sqlpower.sqlobject.SQLTable;
import ca.sqlpower.sqlobject.SQLTypePhysicalProperties;
import ca.sqlpower.sqlobject.SQLTypePhysicalProperties.SQLTypeConstraint;
import ca.sqlpower.sqlobject.SQLTypePhysicalPropertiesProvider.BasicSQLType;
import ca.sqlpower.sqlobject.SQLTypePhysicalPropertiesProvider.PropertyType;
import ca.sqlpower.sqlobject.UserDefinedSQLType;
import ca.sqlpower.util.DefaultUserPrompter;
import ca.sqlpower.util.UserPrompter;
import ca.sqlpower.util.UserPrompter.UserPromptOptions;
import ca.sqlpower.util.UserPrompter.UserPromptResponse;
/**
* An implementation of NewValueMaker that recognizes classes in the Java SE
* library and the SQL Power library. Apps can extend this class to also provide
* awareness for their own types that show up in bean properties.
*/
public class GenericNewValueMaker implements NewValueMaker {
/**
* See doc comment on constructor.
*/
protected final SPObject root;
protected final DataSourceCollection<SPDataSource> pl;
/**
* @param root
* The absolute root object of the new value maker. All SPObjects
* made by this class must be attached to this root object in
* some way so they can be traversed by tests. The objects
* created by this test do not have to be an immediate child of
* the root for cases where they may need a specific type of
* parent or ancestor which can be a child of the root. This object
* must be able to accept children of any type that can be produced by
* this new value maker.
*/
public GenericNewValueMaker(SPObject root) {
this(root, new PlDotIni());
}
public GenericNewValueMaker(SPObject root, DataSourceCollection<SPDataSource> pl) {
this.root = root;
this.pl = pl;
}
protected SPObject getRootObject() {
return root;
}
public Object makeNewValue(Class<?> valueType, Object oldVal, String propName) {
Object newVal; // don't init here so compiler can warn if the following code doesn't always give it a value
if (valueType == Integer.TYPE) {
newVal = ((Integer) oldVal)+1;
} else if (valueType == Long.TYPE) {
newVal = ((Long) oldVal) + 1;
} else if (valueType == Long.class) {
if (oldVal == null) {
newVal = 1L;
} else {
newVal = ((Long) oldVal) + 1;
}
} else if (valueType == Short.class) {
if (oldVal == null) {
newVal = (short) 1;
} else {
newVal = ((Short) oldVal) + 1;
}
} else if (valueType == Double.TYPE) {
newVal = ((Double) oldVal)+1;
} else if (valueType == Integer.class) {
if (oldVal == null) {
newVal = new Integer(1);
} else {
newVal = new Integer((Integer)oldVal+1);
}
} else if (valueType == Double.class) {
if (oldVal == null) {
newVal = new Double(1);
} else {
newVal = new Double((Double)oldVal+1);
}
} else if (valueType == BigDecimal.class) {
if (oldVal != null) {
newVal = new BigDecimal(1).add((BigDecimal) oldVal);
} else {
return new BigDecimal(1);
}
} else if (valueType == Character.TYPE || valueType == Character.class) {
Character c = (Character) oldVal;
if (c == null || c == 'a') {
newVal = 'b';
} else {
newVal = 'a';
}
} else if (valueType == String.class) {
// make sure it's unique
newVal = "new" + oldVal;
} else if (valueType == Boolean.TYPE){
newVal = new Boolean(! ((Boolean) oldVal).booleanValue());
} else if (valueType == Boolean.class) {
if (oldVal == null) {
newVal = Boolean.TRUE;
} else {
newVal = new Boolean(! ((Boolean) oldVal).booleanValue());
}
} else if (valueType == Date.class) {
newVal = new Date(System.currentTimeMillis());
} else if (valueType == File.class) {
newVal = new File("temp" + System.currentTimeMillis());
} else if (valueType == JDBCDataSource.class || valueType == SPDataSource.class) {
String name = "regression_test";
if (oldVal != null && ((SPDataSource) oldVal).getName().equals(name)) {
name = "Testing data source";
if (pl.getDataSource(name) != null) {
newVal = pl.getDataSource(name);
} else {
newVal = new JDBCDataSource(this.pl);
((SPDataSource)newVal).setName(name);
this.pl.addDataSource((JDBCDataSource)newVal);
}
} else {
newVal = pl.getDataSource(name);
if (newVal == null) {
newVal = new JDBCDataSource(this.pl);
((SPDataSource)newVal).setName(name);
this.pl.addDataSource((JDBCDataSource)newVal);
}
}
} else if (valueType == Font.class) {
newVal = Font.decode("Dialog");
if (newVal.equals(oldVal)) {
newVal = ((Font) newVal).deriveFont(((Font) newVal).getSize2D() + 1f);
}
} else if (valueType.isAssignableFrom(NumberFormat.class)) {
if(oldVal == NumberFormat.getCurrencyInstance()) {
newVal = NumberFormat.getPercentInstance();
} else {
newVal = NumberFormat.getCurrencyInstance();
}
} else if(valueType == SimpleDateFormat.class) {
if(oldVal == SimpleDateFormat.getDateTimeInstance()) {
newVal = SimpleDateFormat.getDateInstance();
} else {
newVal = SimpleDateFormat.getDateTimeInstance();
}
} else if (SQLColumn.class.isAssignableFrom(valueType)) {
// Objects like SPObject or SQLObject may come in here
SQLColumn sqlCol = new SQLColumn();
sqlCol.setName("testing!");
SQLTable table = (SQLTable) makeNewValue(SQLTable.class, null, "Parent of column");
try {
table.addColumn(sqlCol);
} catch (SQLObjectException e) {
throw new SQLObjectRuntimeException(e);
}
table.setPopulated(true);
newVal = sqlCol;
} else if (valueType == SQLTable.class) {
SQLTable table = new SQLTable();
table.setName("Generated testing table");
table.setPopulated(true);
SQLDatabase db = (SQLDatabase) makeNewValue(SQLDatabase.class, null, "parent of table");
db.addTable(table);
newVal = table;
} else if (valueType == SQLDatabase.class) {
JDBCDataSource argDataSource = new JDBCDataSource(this.pl);
argDataSource.setName("Testing data source");
SQLDatabase db = new SQLDatabase();
db.setDataSource(argDataSource);
SQLObjectRoot sqlRoot = (SQLObjectRoot) makeNewValue(SQLObjectRoot.class, null, "parent of db");
sqlRoot.addDatabase(db, 0);
newVal = db;
} else if (valueType == SQLObjectRoot.class) {
SQLObjectRoot sqlRoot = new SQLObjectRoot();
root.addChild(sqlRoot, 0);
newVal = sqlRoot;
} else if (valueType == Column.class) {
Column col = new Column();
col.setName("Generated testing column index");
SQLIndex index = (SQLIndex) makeNewValue(SQLIndex.class, null, "parent of column");
index.setPopulated(true);
index.addIndexColumn(col);
newVal = col;
} else if (valueType == SQLIndex.class) {
SQLIndex index = new SQLIndex();
index.setName("a new index");
SQLTable table = (SQLTable) makeNewValue(SQLTable.class, null, "parent of index");
table.addIndex(index);
table.setPopulated(true);
newVal = index;
} else if (valueType == ColumnMapping.class) {
ColumnMapping mapping = new ColumnMapping();
mapping.setName("Generated testing mapping");
SQLRelationship rel = (SQLRelationship) makeNewValue(SQLRelationship.class, null, "parent of column mapping");
rel.addMapping(mapping);
SQLColumn pkCol = (SQLColumn) makeNewValue(SQLColumn.class, null, "pk column");
SQLColumn fkCol = (SQLColumn) makeNewValue(SQLColumn.class, null, "pk column");
mapping.setPkColumn(pkCol);
mapping.setFkColumn(fkCol);
newVal = mapping;
} else if (valueType == SQLRelationship.class) {
SQLRelationship rel = new SQLRelationship();
SQLTable parent = (SQLTable) makeNewValue(SQLTable.class, null, "parent of relationship");
SQLTable child = (SQLTable) makeNewValue(SQLTable.class, null, "child of relationship");
try {
rel.attachRelationship(parent, child, true);
} catch (SQLObjectException e) {
throw new RuntimeException("Trying to create a new relationship for testing", e);
}
newVal = rel;
} else if (valueType == SQLSchema.class) {
SQLSchema schema = new SQLSchema(true);
schema.setName("A new schema for testing");
SQLDatabase db = (SQLDatabase) makeNewValue(SQLDatabase.class, null, "Schema database");
db.addSchema(schema);
newVal = schema;
} else if (valueType == SQLCatalog.class) {
SQLDatabase db = (SQLDatabase) makeNewValue(SQLDatabase.class, null, "Schema database");
SQLCatalog catalog = new SQLCatalog(db, "catalog for test", true);
db.addCatalog(catalog);
newVal = catalog;
} else if (valueType == SPObject.class) {
newVal = makeNewValue(SQLDatabase.class, null, "SPObject of some kind");
} else if (valueType == SQLObject.class) {
newVal = makeNewValue(SQLColumn.class, null, "SQLObject of some kind");
} else if (valueType == SQLCheckConstraint.class) {
SQLTypePhysicalProperties properties =
(SQLTypePhysicalProperties) makeNewValue(SQLTypePhysicalProperties.class, null, "SQLTypePhysicalProperties as parent of SQLCheckConstraint");
SQLCheckConstraint constraint = new SQLCheckConstraint(
(String) makeNewValue(String.class, null, "SQLCheckConstraint - name"),
(String) makeNewValue(String.class, null, "SQLCheckConstraint - constraint"));
properties.addCheckConstraint(constraint);
newVal = constraint;
} else if (valueType == SQLEnumeration.class) {
SQLTypePhysicalProperties properties =
(SQLTypePhysicalProperties) makeNewValue(SQLTypePhysicalProperties.class, null, "SQLTypePhysicalProperties as parent of SQLEnumeration");
SQLEnumeration enumeration = new SQLEnumeration((String) makeNewValue(String.class, null, "SQLEnumeration - name"));
properties.addEnumeration(enumeration);
newVal = enumeration;
} else if (valueType == SQLCheckConstraintContainer.class) {
newVal = makeNewValue(SQLTypePhysicalProperties.class, oldVal, propName);
} else if (valueType == Throwable.class) {
newVal = new SQLObjectException("Test Exception");
} else if (valueType == UserPrompter.class) {
newVal = new DefaultUserPrompter(UserPromptOptions.OK_NEW_NOTOK_CANCEL, UserPromptResponse.CANCEL, null);
} else if (valueType == Point.class) {
Point p = new Point(24, 42);
if (p.equals(oldVal)) {
p.translate(1, 1);
}
newVal = p;
} else if (valueType == Point2D.class) {
Point2D point = new Point2D(){
private double x;
private double y;
@Override
public void setLocation(double x, double y) {
this.x = x;
this.y = y;
}
@Override
public double getY() {
return y;
}
@Override
public double getX() {
return x;
}
};
if (oldVal == null) {
point.setLocation(0, 0);
} else {
point.setLocation(((Point2D) oldVal).getX() + 1, ((Point2D) oldVal).getY() - 1);
}
newVal = point;
} else if (valueType.equals(Image.class)) {
newVal = new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB);
} else if (valueType.equals(Olap4jDataSource.class)) {
Olap4jDataSource ds = new Olap4jDataSource(new StubDataSourceCollection<SPDataSource>());
ds.setName("Testing OLAP data source");
newVal = ds;
} else if (valueType.equals(SQLGroupFunction.class)) {
if (oldVal.equals(SQLGroupFunction.COUNT)) {
newVal = SQLGroupFunction.GROUP_BY;
} else {
newVal = SQLGroupFunction.COUNT;
}
} else if (valueType == Deferrability.class) {
if (oldVal.equals(Deferrability.INITIALLY_DEFERRED)) {
newVal = Deferrability.INITIALLY_IMMEDIATE;
} else {
newVal = Deferrability.INITIALLY_DEFERRED;
}
} else if (valueType == UpdateDeleteRule.class) {
if (oldVal.equals(UpdateDeleteRule.CASCADE)) {
newVal = UpdateDeleteRule.NO_ACTION;
} else {
newVal = UpdateDeleteRule.CASCADE;
}
} else if (valueType == SQLImportedKey.class) {
SQLRelationship relationship = (SQLRelationship) makeNewValue(SQLRelationship.class, null, "parent of importedKey");
SQLImportedKey key = relationship.getForeignKey();
SQLTable table = (SQLTable) makeNewValue(SQLTable.class, null, "parent of imported key");
table.addImportedKey(key);
newVal = key;
} else if (valueType == AscendDescend.class) {
if (oldVal.equals(AscendDescend.ASCENDING)) {
newVal = AscendDescend.DESCENDING;
} else {
newVal = AscendDescend.ASCENDING;
}
} else if (valueType == Rectangle.class) {
Rectangle r = new Rectangle(12, 34, 56, 78);
if (r.equals(oldVal)) {
r.translate(1, 1);
}
newVal = r;
} else if (valueType == Color.class) {
Color rgb = new Color(33, 66, 99);
if (rgb.getRGB() == ((Color) oldVal).getRGB()) {
rgb = rgb.brighter();
}
newVal = rgb;
} else if (valueType == Dimension.class) {
Dimension d = new Dimension(12, 34);
if (d.equals(oldVal)) {
d.width++;
}
newVal = d;
} else if (valueType == BasicSQLType.class) {
if (oldVal != BasicSQLType.OTHER) {
newVal = BasicSQLType.OTHER;
} else {
newVal = BasicSQLType.TEXT;
}
} else if (valueType == UserDefinedSQLType.class) {
UserDefinedSQLType userDefinedSQLType = new UserDefinedSQLType();
UserDefinedSQLType oldType = (UserDefinedSQLType) oldVal;
if (oldType != null && oldType.getType() != null) {
userDefinedSQLType.setType(oldType.getType() + 1);
} else {
userDefinedSQLType.setType(1);
}
newVal = userDefinedSQLType;
root.addChild((SPObject) newVal, root.getChildren(UserDefinedSQLType.class).size());
} else if (valueType == SQLTypePhysicalProperties.class) {
// XXX Uses a random string so that each platform will be different. The interaction
// of identical platforms is tested for specifically.
SQLTypePhysicalProperties properties = new SQLTypePhysicalProperties(UUID.randomUUID().toString());
UserDefinedSQLType udt =
(UserDefinedSQLType) makeNewValue(UserDefinedSQLType.class, null, "UserDefinedSQLType as parent of SQLTypePhysicalProperties");
try {
udt.addChild(properties);
} catch (SQLObjectException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
newVal = properties;
} else if (valueType == SQLTypeConstraint.class) {
if (oldVal != SQLTypeConstraint.NONE) {
newVal = SQLTypeConstraint.NONE;
} else {
newVal = SQLTypeConstraint.CHECK;
}
} else if (valueType == String[].class) {
String[] array = {"test1", "test2", "test3"};
newVal = array;
} else if (valueType == PropertyType.class) {
if (oldVal != PropertyType.NOT_APPLICABLE) {
newVal = PropertyType.NOT_APPLICABLE;
} else {
newVal = PropertyType.VARIABLE;
}
} else if (Exception.class.isAssignableFrom(valueType)) {
newVal = new Exception("Testing Exception");
} else if (valueType == List.class) {
newVal = Arrays.asList("one","two","three");
} else {
throw new RuntimeException(
"This new value maker doesn't handle type " + valueType.getName() +
" (for property " + propName + ")");
}
return newVal;
}
}