ALF-7260: schema comparator

* replace path/push/pop mechanism as it doesn't work well at reporting where differences/validation errors occur.
* add getParent() to DbObject - so that a path-style identifier can be deduced for a DbObject when needed
* add DbProperty to specify a specific DbObject's property and value -- acts as a schema location pointer
* refactored Result code (need difference result and validation error result)





git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@31527 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Matt Ward 2011-10-27 18:07:06 +00:00
parent 385003c6c9
commit 723fe98cf2
37 changed files with 1022 additions and 613 deletions

View File

@ -37,11 +37,11 @@ public interface ComparisonUtils
*/ */
DbObject findSameObjectAs(Collection<? extends DbObject> objects, final DbObject objToFind); DbObject findSameObjectAs(Collection<? extends DbObject> objects, final DbObject objToFind);
void compareSimpleCollections(Collection<? extends Object> leftCollection, void compareSimpleCollections(DbProperty leftProperty, DbProperty rightProperty,
Collection<? extends Object> rightCollection, DiffContext ctx, Strength strength); DiffContext ctx, Strength strength);
/** /**
* Compare collections, reporting differences using the default {@link Result.Strength} * Compare collections, reporting differences using the default {@link Difference.Strength}
* *
* @see #compareCollections(Collection, Collection, Differences, Strength) * @see #compareCollections(Collection, Collection, Differences, Strength)
*/ */
@ -50,7 +50,7 @@ public interface ComparisonUtils
/** /**
* Compare collections of {@link DbObject}s using their {@link DbObject#diff(DbObject, Differences)} method. * Compare collections of {@link DbObject}s using their {@link DbObject#diff(DbObject, Differences)} method.
* Differences are reported using the specified {@link Result.Strength}. * Differences are reported using the specified {@link Difference.Strength}.
* *
* @param leftCollection * @param leftCollection
* @param rightCollection * @param rightCollection
@ -66,7 +66,7 @@ public interface ComparisonUtils
* *
* @see #compareSimple(Object, Object, Differences, Strength) * @see #compareSimple(Object, Object, Differences, Strength)
*/ */
void compareSimple(Object left, Object right, DiffContext ctx); void compareSimple(DbProperty left, DbProperty right, DiffContext ctx);
/** /**
* Compare two 'simple' (i.e. non-{@link DbObject} objects) using their {@link Object#equals(Object)} method * Compare two 'simple' (i.e. non-{@link DbObject} objects) using their {@link Object#equals(Object)} method
@ -77,6 +77,6 @@ public interface ComparisonUtils
* @param differences * @param differences
* @param strength * @param strength
*/ */
void compareSimple(Object left, Object right, DiffContext ctx, Strength strength); void compareSimple(DbProperty left, DbProperty right, DiffContext ctx, Strength strength);
} }

View File

@ -18,27 +18,14 @@
*/ */
package org.alfresco.util.schemacomp; package org.alfresco.util.schemacomp;
import org.alfresco.util.schemacomp.model.Column;
import org.alfresco.util.schemacomp.model.DbObject; import org.alfresco.util.schemacomp.model.DbObject;
import org.alfresco.util.schemacomp.model.ForeignKey;
import org.alfresco.util.schemacomp.model.Index;
import org.alfresco.util.schemacomp.model.PrimaryKey;
import org.alfresco.util.schemacomp.model.Schema;
import org.alfresco.util.schemacomp.model.Sequence;
import org.alfresco.util.schemacomp.model.Table;
/** /**
* Defines a visitor that can operate on a DbObject. * Defines a visitor that can operate on a DbObject.
*
* @author Matt Ward * @author Matt Ward
*/ */
public interface DbObjectVisitor public interface DbObjectVisitor
{ {
void visit(DbObject dbObject); void visit(DbObject dbObject);
// void visit(Column column);
// void visit(ForeignKey fk);
// void visit(Index index);
// void visit(PrimaryKey pk);
// void visit(Schema schema);
// void visit(Sequence sequence);
// void visit(Table table);
} }

View File

@ -0,0 +1,239 @@
/*
* Copyright (C) 2005-2011 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.util.schemacomp;
import org.alfresco.util.schemacomp.model.DbObject;
import org.apache.commons.beanutils.PropertyUtils;
/**
* A pointer to a specific DbObject property and its value (at time of creating the DbProperty object).
*
* @author Matt Ward
*/
public class DbProperty
{
private final DbObject dbObject;
private final String propertyName;
private final Object propertyValue;
/**
* Full constructor allowing control over whether the property name should be indexed (e.g. colours[3]),
* whether the current value of the property should be retrieved automatically or whether to use the
* supplied value (useful when performing comparisons - construct one with a particular/expected value and
* construct another with the current value by reflection).
* <p>
* The public constructors provide a more usable API with select sets of arguments.
*
* @param dbObject
* @param propertyName
* @param propertyValue
*/
protected DbProperty(DbObject dbObject, String propertyName, int index, boolean useSuppliedValue, Object propertyValue)
{
if (dbObject == null)
{
throw new IllegalArgumentException("dbObject cannot be null.");
}
this.dbObject = dbObject;
if (propertyName == null)
{
if (index > -1 || useSuppliedValue)
{
throw new IllegalArgumentException("propertyName cannot be null.");
}
}
if (index > -1)
{
this.propertyName = propertyName+"["+index+"]";
}
else
{
this.propertyName = propertyName;
}
// Unfortunetely, this boolean is required, since we may want to set the property value to null.
if (useSuppliedValue)
{
this.propertyValue = propertyValue;
}
else if (propertyName != null)
{
try
{
this.propertyValue = PropertyUtils.getProperty(dbObject, this.propertyName);
}
catch (Throwable error)
{
throw new IllegalArgumentException("Cannot get value for property named \"" + propertyName + "\"", error);
}
}
else
{
// No property is being referred to by this object.
this.propertyValue = null;
}
}
/**
* Construct a pointer to a database object only (no property within).
*
* @param dbObject
*/
public DbProperty(DbObject dbObject)
{
this(dbObject, null, -1, false, null);
}
/**
* Create a DbProperty by supplying the DbObject and the property name. The
* value at time of creation will be populate automatically.
*
* @param dbObject
* @param propertyName
*/
public DbProperty(DbObject dbObject, String propertyName)
{
this(dbObject, propertyName, -1, false, null);
}
/**
* Create a DbProperty with an indexed value, e.g. for propertyName "myCollection" and
* index 4, the propertyName will be converted to "myCollection[4]" and the propertValue
* will be populated with the value at index 4 of myCollection.
*
* @param dbObject
* @param propertyName
* @param index
*/
public DbProperty(DbObject dbObject, String propertyName, int index)
{
this(dbObject, propertyName, index, false, null);
}
/**
* @return the dbObject
*/
public DbObject getDbObject()
{
return this.dbObject;
}
/**
* @return the propertyName
*/
public String getPropertyName()
{
return this.propertyName;
}
/**
* @return the propertyValue
*/
public Object getPropertyValue()
{
return this.propertyValue;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((this.dbObject == null) ? 0 : this.dbObject.hashCode());
result = prime * result + ((this.propertyName == null) ? 0 : this.propertyName.hashCode());
result = prime * result
+ ((this.propertyValue == null) ? 0 : this.propertyValue.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
DbProperty other = (DbProperty) obj;
if (this.dbObject == null)
{
if (other.dbObject != null) return false;
}
else if (!this.dbObject.equals(other.dbObject)) return false;
if (this.propertyName == null)
{
if (other.propertyName != null) return false;
}
else if (!this.propertyName.equals(other.propertyName)) return false;
if (this.propertyValue == null)
{
if (other.propertyValue != null) return false;
}
else if (!this.propertyValue.equals(other.propertyValue)) return false;
return true;
}
@Override
public String toString()
{
return "DbProperty [dbObject=" + this.dbObject + ", propertyName=" + this.propertyName
+ ", propertyValue=" + this.propertyValue + "]";
}
/**
* Work backwards from this DbProperty's DbObject to the root object to create a path in the
* following format:
* <p>
* root.child.grandchild[...].property
* <p>
* e.g. myschema.person.age.nullable
* <p>
* This isn't exactly the same as a FQ database object name, for example the property name could be indexed:
* <p>
* e.g. myschema.person.pk_person.columnNames[2]
* <p>
* to reflect the third column name in the primary key named "pk_person" on the person table.
*
* @return String path
*/
public String getPath()
{
StringBuffer sb = new StringBuffer();
if (getPropertyName() != null)
{
sb.append(".");
sb.append(getPropertyName());
}
for (DbObject pathElement = dbObject; pathElement != null; pathElement = pathElement.getParent())
{
sb.insert(0, pathElement.getName());
if (pathElement.getParent() != null)
{
sb.insert(0, ".");
}
}
return sb.toString();
}
}

View File

@ -0,0 +1,115 @@
/*
* Copyright (C) 2005-2011 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.util.schemacomp;
import static org.junit.Assert.assertEquals;
import java.util.Arrays;
import java.util.List;
import org.alfresco.util.schemacomp.model.AbstractDbObject;
import org.alfresco.util.schemacomp.model.DbObject;
import org.junit.Test;
import org.mockito.Mockito;
public class DbPropertyTest
{
@Test(expected = IllegalArgumentException.class)
public void cannotHaveNullDbObject()
{
new DbProperty(null, "theProperty");
}
@Test
public void propertyValueCanBeRetrievedByReflection()
{
DbObjectWithIndexedProp dbo = Mockito.mock(DbObjectWithIndexedProp.class);
Mockito.when(dbo.getTheProperty()).thenReturn("This is the property value");
DbProperty dbProperty = new DbProperty(dbo, "theProperty");
assertEquals("This is the property value", dbProperty.getPropertyValue());
}
@Test
public void indexedPropertyValueCanBeRetrievedByReflection()
{
DbObjectWithIndexedProp dbo = Mockito.mock(DbObjectWithIndexedProp.class);
Mockito.when(dbo.getColours()).thenReturn(Arrays.asList("red", "green", "blue"));
DbProperty greenProperty = new DbProperty(dbo, "colours[1]");
DbProperty blueProperty = new DbProperty(dbo, "colours", 2);
assertEquals("green", greenProperty.getPropertyValue());
assertEquals("blue", blueProperty.getPropertyValue());
}
@Test
public void canGetPath()
{
new MyDbObject("root", 1).
add(new MyDbObject("child", 2)).
add(new MyDbObject("grandchild", 3)).
add(new MyDbObject("greatgrandchild", 4));
DbProperty levelProp = new DbProperty(MyDbObject.lastAdded, "level");
assertEquals("Incorrect path", "root.child.grandchild.greatgrandchild.level", levelProp.getPath());
DbProperty greatGrandChildProp = new DbProperty(MyDbObject.lastAdded);
assertEquals("Incorrect path", "root.child.grandchild.greatgrandchild", greatGrandChildProp.getPath());
}
private interface DbObjectWithIndexedProp extends DbObject
{
String getTheProperty();
List<String> getColours();
}
public static class MyDbObject extends AbstractDbObject
{
public static MyDbObject lastAdded;
private int level;
public MyDbObject(String name, int level)
{
super(null, name);
this.level = level;
}
@Override
public void accept(DbObjectVisitor visitor)
{
}
public MyDbObject add(MyDbObject child)
{
child.setParent(this);
lastAdded = child;
return child;
}
public int getLevel()
{
return this.level;
}
}
}

View File

@ -19,10 +19,11 @@
package org.alfresco.util.schemacomp; package org.alfresco.util.schemacomp;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import org.alfresco.util.schemacomp.Result.Strength; import org.alfresco.util.schemacomp.Result.Strength;
import org.alfresco.util.schemacomp.Result.Where; import org.alfresco.util.schemacomp.Difference.Where;
import org.alfresco.util.schemacomp.model.DbObject; import org.alfresco.util.schemacomp.model.DbObject;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate; import org.apache.commons.collections.Predicate;
@ -54,42 +55,60 @@ public class DefaultComparisonUtils implements ComparisonUtils
@Override @Override
public void compareSimpleCollections(Collection<? extends Object> leftCollection, public void compareSimpleCollections(DbProperty leftProp,
Collection<? extends Object> rightCollection, DiffContext ctx, Strength strength) DbProperty rightProp, DiffContext ctx, Strength strength)
{ {
Differences differences = ctx.getDifferences(); @SuppressWarnings("unchecked")
for (Object leftObj : leftCollection) Collection<? extends Object> leftCollection = (Collection<? extends Object>) leftProp.getPropertyValue();
@SuppressWarnings("unchecked")
Collection<? extends Object> rightCollection = (Collection<? extends Object>) rightProp.getPropertyValue();
// TODO: Temporary code during refactoring
ArrayList<? extends Object> leftList = new ArrayList<Object>(leftCollection);
ArrayList<? extends Object> rightList = new ArrayList<Object>(rightCollection);
Results differences = ctx.getDifferences();
for (int leftIndex = 0; leftIndex < leftList.size(); leftIndex++)
{ {
if (rightCollection.contains(leftObj)) Object leftObj = leftList.get(leftIndex);
DbProperty leftIndexedProp = new DbProperty(leftProp.getDbObject(), leftProp.getPropertyName(), leftIndex);
int rightIndex;
if ((rightIndex = rightList.indexOf(leftObj)) != -1)
{ {
// The same valued object in the right hand collection as in the left. // The same valued object in the right hand collection as in the left.
// Note: it isn't possible to determine a result of Where.IN_BOTH_BUT_DIFFERENCE // Note: it isn't possible to determine a result of Where.IN_BOTH_BUT_DIFFERENCE
// with a 'simple' value as there is no way of knowing if the term represents the same value // with a 'simple' value as there is no way of knowing if the term represents the same value
// (e.g. two strings {red_value, green_value}, are these meant to be the same or different?) // (e.g. two strings {red_value, green_value}, are these meant to be the same or different?)
differences.add(Where.IN_BOTH_NO_DIFFERENCE, leftObj, leftObj, strength); DbProperty rightIndexedProp = new DbProperty(rightProp.getDbObject(), rightProp.getPropertyName(), rightIndex);
differences.add(Where.IN_BOTH_NO_DIFFERENCE, leftIndexedProp, rightIndexedProp, strength);
} }
else else
{ {
// No equivalent object in the right hand collection. // No equivalent object in the right hand collection.
differences.add(Where.ONLY_IN_LEFT, leftObj, null, strength); // Using rightIndexedProperty would result in index out of bounds error.
differences.add(Where.ONLY_IN_LEFT, leftIndexedProp, rightProp, strength);
} }
} }
// Identify objects in the right collection but not the left // Identify objects in the right collection but not the left
for (Object rightObj : rightCollection) for (int rightIndex = 0; rightIndex < rightList.size(); rightIndex++)
{ {
Object rightObj = rightList.get(rightIndex);
if (!leftCollection.contains(rightObj)) if (!leftCollection.contains(rightObj))
{ {
DbProperty rightIndexedProp = new DbProperty(rightProp.getDbObject(), rightProp.getPropertyName(), rightIndex);
// No equivalent object in the left hand collection. // No equivalent object in the left hand collection.
differences.add(Where.ONLY_IN_RIGHT, null, rightObj, strength); differences.add(Where.ONLY_IN_RIGHT, leftProp, rightIndexedProp, strength);
} }
} }
} }
/** /**
* Compare collections, reporting differences using the default {@link Result.Strength} * Compare collections, reporting differences using the default {@link Difference.Strength}
* *
* @see #compareCollections(Collection, Collection, Differences, Strength) * @see #compareCollections(Collection, Collection, Results, Strength)
*/ */
@Override @Override
public void compareCollections(Collection<? extends DbObject> leftCollection, public void compareCollections(Collection<? extends DbObject> leftCollection,
@ -99,8 +118,8 @@ public class DefaultComparisonUtils implements ComparisonUtils
} }
/** /**
* Compare collections of {@link DbObject}s using their {@link DbObject#diff(DbObject, Differences)} method. * Compare collections of {@link DbObject}s using their {@link DbObject#diff(DbObject, Results)} method.
* Differences are reported using the specified {@link Result.Strength}. * Differences are reported using the specified {@link Difference.Strength}.
* *
* @param leftCollection * @param leftCollection
* @param rightCollection * @param rightCollection
@ -111,7 +130,7 @@ public class DefaultComparisonUtils implements ComparisonUtils
public void compareCollections(Collection<? extends DbObject> leftCollection, public void compareCollections(Collection<? extends DbObject> leftCollection,
Collection<? extends DbObject> rightCollection, DiffContext ctx, Strength strength) Collection<? extends DbObject> rightCollection, DiffContext ctx, Strength strength)
{ {
Differences differences = ctx.getDifferences(); Results differences = ctx.getDifferences();
for (DbObject leftObj : leftCollection) for (DbObject leftObj : leftCollection)
{ {
DbObject rightObj = findSameObjectAs(rightCollection, leftObj); DbObject rightObj = findSameObjectAs(rightCollection, leftObj);
@ -125,17 +144,19 @@ public class DefaultComparisonUtils implements ComparisonUtils
else else
{ {
// No equivalent object in the right hand collection. // No equivalent object in the right hand collection.
differences.add(Where.ONLY_IN_LEFT, leftObj, null, strength); differences.add(Where.ONLY_IN_LEFT, new DbProperty(leftObj, null), null, strength);
} }
} }
// Identify objects in the right collection but not the left // Identify objects in the right collection but not the left
for (DbObject rightObj : rightCollection) for (DbObject rightObj : rightCollection)
{ {
if (!leftCollection.contains(rightObj)) DbObject leftObj = findSameObjectAs(leftCollection, rightObj);
if (leftObj == null)
{ {
// No equivalent object in the left hand collection. // No equivalent object in the left hand collection.
differences.add(Where.ONLY_IN_RIGHT, null, rightObj, strength); differences.add(Where.ONLY_IN_RIGHT, null, new DbProperty(rightObj, null), strength);
} }
} }
} }
@ -143,10 +164,10 @@ public class DefaultComparisonUtils implements ComparisonUtils
/** /**
* Compare two simple objects. Differences are reported using the default Result.Strength. * Compare two simple objects. Differences are reported using the default Result.Strength.
* *
* @see #compareSimple(Object, Object, Differences, Strength) * @see #compareSimple(Object, Object, Results, Strength)
*/ */
@Override @Override
public void compareSimple(Object left, Object right, DiffContext ctx) public void compareSimple(DbProperty left, DbProperty right, DiffContext ctx)
{ {
compareSimple(left, right, ctx, null); compareSimple(left, right, ctx, null);
} }
@ -161,11 +182,16 @@ public class DefaultComparisonUtils implements ComparisonUtils
* @param strength * @param strength
*/ */
@Override @Override
public void compareSimple(Object left, Object right, DiffContext ctx, Strength strength) public void compareSimple(DbProperty leftProperty, DbProperty rightProperty, DiffContext ctx, Strength strength)
{ {
Where where = null; Where where = null;
Object left = leftProperty.getPropertyValue();
checkNotDbObject(left);
Object right = rightProperty.getPropertyValue();
checkNotDbObject(right);
if (left == right) if (left == right)
{ {
// Same object, or both nulls // Same object, or both nulls
@ -194,6 +220,19 @@ public class DefaultComparisonUtils implements ComparisonUtils
} }
} }
ctx.getDifferences().add(where, left, right, strength); ctx.getDifferences().add(where, leftProperty, rightProperty, strength);
}
/**
* @param obj
*/
private void checkNotDbObject(Object obj)
{
if (obj != null && DbObject.class.isAssignableFrom(obj.getClass()))
{
throw new IllegalArgumentException(
"Property value is a DbObject - this method shouldn't be used to compare this type: " + obj);
}
} }
} }

View File

@ -30,8 +30,9 @@ import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.alfresco.util.schemacomp.Difference.Where;
import org.alfresco.util.schemacomp.Result.Strength; import org.alfresco.util.schemacomp.Result.Strength;
import org.alfresco.util.schemacomp.Result.Where; import org.alfresco.util.schemacomp.model.AbstractDbObject;
import org.alfresco.util.schemacomp.model.DbObject; import org.alfresco.util.schemacomp.model.DbObject;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.junit.Before; import org.junit.Before;
@ -48,7 +49,7 @@ import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class) @RunWith(MockitoJUnitRunner.class)
public class DefaultComparisonUtilsTest public class DefaultComparisonUtilsTest
{ {
private @Mock Differences differences; private @Mock Results differences;
private DefaultComparisonUtils comparisonUtils; private DefaultComparisonUtils comparisonUtils;
private DiffContext ctx; private DiffContext ctx;
private @Mock Dialect dialect; private @Mock Dialect dialect;
@ -63,22 +64,27 @@ public class DefaultComparisonUtilsTest
@Test @Test
public void compareSimple() public void compareSimple()
{ {
comparisonUtils.compareSimple(null, null, ctx, Strength.ERROR); comparisonUtils.compareSimple(prop(null), prop(null), ctx, Strength.ERROR);
verify(differences).add(Where.IN_BOTH_NO_DIFFERENCE, null, null, Strength.ERROR); verify(differences).add(Where.IN_BOTH_NO_DIFFERENCE, prop(null), prop(null), Strength.ERROR);
comparisonUtils.compareSimple("not_null_string", "not_null_string", ctx, Strength.ERROR); comparisonUtils.compareSimple(prop("not_null_string"), prop("not_null_string"), ctx, Strength.ERROR);
verify(differences).add(Where.IN_BOTH_NO_DIFFERENCE, "not_null_string", "not_null_string", Strength.ERROR); verify(differences).add(Where.IN_BOTH_NO_DIFFERENCE, prop("not_null_string"), prop("not_null_string"), Strength.ERROR);
comparisonUtils.compareSimple("left", "right", ctx, Strength.ERROR); comparisonUtils.compareSimple(prop("left"), prop("right"), ctx, Strength.ERROR);
verify(differences).add(Where.IN_BOTH_BUT_DIFFERENCE, "left", "right", Strength.ERROR); verify(differences).add(Where.IN_BOTH_BUT_DIFFERENCE, prop("left"), prop("right"), Strength.ERROR);
comparisonUtils.compareSimple("left", null, ctx, Strength.ERROR); comparisonUtils.compareSimple(prop("left"), prop(null), ctx, Strength.ERROR);
verify(differences).add(Where.ONLY_IN_LEFT, "left", null, Strength.ERROR); verify(differences).add(Where.ONLY_IN_LEFT, prop("left"), prop(null), Strength.ERROR);
comparisonUtils.compareSimple(null, "right", ctx, Strength.ERROR); comparisonUtils.compareSimple(prop(null), prop("right"), ctx, Strength.ERROR);
verify(differences).add(Where.ONLY_IN_RIGHT, null, "right", Strength.ERROR); verify(differences).add(Where.ONLY_IN_RIGHT, prop(null), prop("right"), Strength.ERROR);
} }
public DbProperty prop(String propValue)
{
DbObject dbo = new DbObjectWithCollection("dbo", null);
return dbPropForValue(dbo, "someProperty", propValue);
}
@Test @Test
public void compareCollections() public void compareCollections()
@ -105,8 +111,8 @@ public class DefaultComparisonUtilsTest
verify(db4).diff(db4, ctx, Strength.ERROR); verify(db4).diff(db4, ctx, Strength.ERROR);
// Objects in only one collections are marked as such // Objects in only one collections are marked as such
verify(differences).add(Where.ONLY_IN_LEFT, db2, null, Strength.ERROR); verify(differences).add(Where.ONLY_IN_LEFT, new DbProperty(db2), null, Strength.ERROR);
verify(differences).add(Where.ONLY_IN_RIGHT, null, db3, Strength.ERROR); verify(differences).add(Where.ONLY_IN_RIGHT, null, new DbProperty(db3), Strength.ERROR);
} }
@ -124,6 +130,8 @@ public class DefaultComparisonUtilsTest
leftCollection.add(subCollectionLeft); leftCollection.add(subCollectionLeft);
leftCollection.add(456); leftCollection.add(456);
leftCollection.add("left only"); leftCollection.add("left only");
DbObject leftDbObj = new DbObjectWithCollection("left", leftCollection);
DbProperty leftCollProp = new DbProperty(leftDbObj, "collection");
Collection<Object> rightCollection = new ArrayList<Object>(); Collection<Object> rightCollection = new ArrayList<Object>();
rightCollection.add(123); rightCollection.add(123);
@ -133,20 +141,59 @@ public class DefaultComparisonUtilsTest
rightCollection.add("right only"); rightCollection.add("right only");
rightCollection.add("both"); rightCollection.add("both");
rightCollection.add("one more right only"); rightCollection.add("one more right only");
DbObject rightDbObj = new DbObjectWithCollection("right", rightCollection);
DbProperty rightCollProp = new DbProperty(rightDbObj, "collection");
comparisonUtils.compareSimpleCollections(leftCollection, rightCollection, ctx, Strength.WARN); comparisonUtils.compareSimpleCollections(leftCollProp, rightCollProp, ctx, Strength.WARN);
verify(differences).add(Where.IN_BOTH_NO_DIFFERENCE, 123, 123, Strength.WARN);
verify(differences).add(Where.IN_BOTH_NO_DIFFERENCE, "both", "both", Strength.WARN);
verify(differences).add(Where.IN_BOTH_NO_DIFFERENCE, subCollectionLeft, subCollectionRight, Strength.WARN);
verify(differences).add(Where.ONLY_IN_LEFT, 456, null, Strength.WARN);
verify(differences).add(Where.ONLY_IN_LEFT, "left only", null, Strength.WARN);
verify(differences).add(Where.ONLY_IN_RIGHT, null, 789, Strength.WARN); verify(differences).add(
verify(differences).add(Where.ONLY_IN_RIGHT, null, "right only", Strength.WARN); Where.IN_BOTH_NO_DIFFERENCE,
verify(differences).add(Where.ONLY_IN_RIGHT, null, "one more right only", Strength.WARN); dbPropForValue(leftDbObj, "collection[0]", 123),
dbPropForValue(rightDbObj, "collection[0]", 123),
Strength.WARN);
verify(differences).add(
Where.IN_BOTH_NO_DIFFERENCE,
dbPropForValue(leftDbObj, "collection[1]", "both"),
dbPropForValue(rightDbObj, "collection[4]", "both"),
Strength.WARN);
verify(differences).add(
Where.IN_BOTH_NO_DIFFERENCE,
dbPropForValue(leftDbObj, "collection[2]", subCollectionLeft),
dbPropForValue(rightDbObj, "collection[2]", subCollectionRight),
Strength.WARN);
verify(differences).add(
Where.ONLY_IN_LEFT,
dbPropForValue(leftDbObj, "collection[3]", 456),
dbPropForValue(rightDbObj, "collection", rightCollection),
Strength.WARN);
verify(differences).add(
Where.ONLY_IN_LEFT,
dbPropForValue(leftDbObj, "collection[4]", "left only"),
dbPropForValue(rightDbObj, "collection", rightCollection),
Strength.WARN);
verify(differences).add(
Where.ONLY_IN_RIGHT,
dbPropForValue(leftDbObj, "collection", leftCollection),
dbPropForValue(rightDbObj, "collection[1]", 789),
Strength.WARN);
verify(differences).add(
Where.ONLY_IN_RIGHT,
dbPropForValue(leftDbObj, "collection", leftCollection),
dbPropForValue(rightDbObj, "collection[3]", "right only"),
Strength.WARN);
verify(differences).add(
Where.ONLY_IN_RIGHT,
dbPropForValue(leftDbObj, "collection", leftCollection),
dbPropForValue(rightDbObj, "collection[5]", "one more right only"),
Strength.WARN);
} }
private DbProperty dbPropForValue(DbObject obj, String propName, Object propValue)
{
return new DbProperty(obj, propName, -1, true, propValue);
}
@Test @Test
public void findSameObjectAsSuccessfulFind() public void findSameObjectAsSuccessfulFind()
@ -194,4 +241,26 @@ public class DefaultComparisonUtilsTest
} }
return dbObjects; return dbObjects;
} }
public static class DbObjectWithCollection extends AbstractDbObject
{
private Collection<Object> collection;
public DbObjectWithCollection(String name, Collection<Object> collection)
{
super(null, name);
this.collection = collection;
}
@Override
public void accept(DbObjectVisitor visitor)
{
}
public Collection<Object> getCollection()
{
return this.collection;
}
}
} }

View File

@ -25,21 +25,21 @@ import org.hibernate.dialect.Dialect;
/** /**
* A context made available to schema differencing and validation operations. It supplies information * A context made available to schema differencing and validation operations. It supplies information
* about the {@link Dialect database dialect} that should be used when validating database properties * about the {@link Dialect database dialect} that should be used when validating database properties
* and the {@link Differences} object that should be populated with schema differences and validation errors. * and the {@link Results} object that should be populated with schema differences and validation errors.
* *
* @author Matt Ward * @author Matt Ward
*/ */
public class DiffContext public class DiffContext
{ {
private final Dialect dialect; private final Dialect dialect;
private final Differences differences; private final Results differences;
private final List<ValidationResult> validationResults; private final List<ValidationResult> validationResults;
/** /**
* @param dialect * @param dialect
* @param differences * @param differences
*/ */
public DiffContext(Dialect dialect, Differences differences, List<ValidationResult> validationResults) public DiffContext(Dialect dialect, Results differences, List<ValidationResult> validationResults)
{ {
this.dialect = dialect; this.dialect = dialect;
this.differences = differences; this.differences = differences;
@ -57,7 +57,7 @@ public class DiffContext
/** /**
* @return the differences * @return the differences
*/ */
public Differences getDifferences() public Results getDifferences()
{ {
return this.differences; return this.differences;
} }

View File

@ -0,0 +1,80 @@
/*
* Copyright (C) 2005-2011 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.util.schemacomp;
/**
* Result of a comparison between two database objects.
*
* @author Matt Ward
*/
public final class Difference extends Result
{
/** Specifies the type of differences */
public enum Where { ONLY_IN_LEFT, ONLY_IN_RIGHT, IN_BOTH_NO_DIFFERENCE, IN_BOTH_BUT_DIFFERENCE };
private final Where where;
private final DbProperty left;
private final DbProperty right;
public Difference(Where where, DbProperty left, DbProperty right)
{
this(where, left, right, null);
}
public Difference(Where where, DbProperty left, DbProperty right, Strength strength)
{
super(null);
this.where = where;
this.left = left;
this.right = right;
}
/**
* @return the where
*/
public Where getWhere()
{
return this.where;
}
/**
* @return the left
*/
public DbProperty getLeft()
{
return this.left;
}
/**
* @return the right
*/
public DbProperty getRight()
{
return this.right;
}
@Override
public String toString()
{
return "Difference [where=" + this.where + ", left=" + this.left + ", right=" + this.right
+ ", strength=" + this.strength + "]";
}
}

View File

@ -1,138 +0,0 @@
/*
* Copyright (C) 2005-2011 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.util.schemacomp;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;
import org.alfresco.util.schemacomp.Result.Strength;
import org.alfresco.util.schemacomp.Result.Where;
import org.alfresco.util.schemacomp.model.DbObject;
import org.apache.commons.lang.StringUtils;
/**
* Collects differences so that tools can report on or respond to differences between database schemas.
*
* @author Matt Ward
*/
public class Differences implements Iterable<Result>
{
private final List<Result> items = new ArrayList<Result>();
private final Path path = new Path();
/**
* @see Path
*/
public void pushPath(String component)
{
this.path.push(component);
}
/**
* @see Path
*/
public String popPath()
{
return this.path.pop();
}
/**
* Record a difference between two objects, or specify that an object only appears in either the
* 'left' or 'right' schemas.
*
* @param where The type of difference, see {@link Where}
* @param left Left value, or null if the item appears in the right, but not left schema.
* @param right Right value, or null if the item appears in the left, but not right schema.
* @param strength The Result.Strength of the difference, e.g. WARN or ERROR.
*/
public void add(Where where, Object left, Object right, Strength strength)
{
Result result = new Result(where, left, right, path.getCurrentPath(), strength);
items.add(result);
}
public void add(Where where, Object left, Object right)
{
add(where, left, right, null);
}
/**
* Obtain an iterator for the top-level items held in this schema - since this is a hierarchical model,
* deeper items are obtained by navigating through the top-level items.
*/
@Override
public Iterator<Result> iterator()
{
return items.iterator();
}
/**
* @return How many top-level items are in the schema.
*/
public int size()
{
return items.size();
}
/**
* Specifies where in a database schema a difference occurs - this is largely the same as the fully qualified
* name of a database object, e.g. <code>public.alf_node</code> except that if an object doesn't have a name
* then a suitable label will be provided for that path element.
* <p>
* Elements can be <code>push</code>ed onto the path and <code>pop</code>ped from the path, making it easier for a
* {@link DbObject} to process that object's data as part of a heirachy - the parent object should push an
* appropriate label onto the path for itself, before invoking any child objects'
* {@link DbObject#diff(DbObject, Differences)} method.
*
* @author Matt Ward
*/
private static class Path
{
private Stack<String> components = new Stack<String>();
private String current;
public void push(String component)
{
components.push(component);
makeCurrentPath();
}
public String pop()
{
String component = components.pop();
makeCurrentPath();
return component;
}
public String getCurrentPath()
{
return current;
}
private void makeCurrentPath()
{
current = StringUtils.join(components, ".");
}
}
}

View File

@ -18,77 +18,24 @@
*/ */
package org.alfresco.util.schemacomp; package org.alfresco.util.schemacomp;
/** /**
* Result of a comparison between two database objects. * Base class for the result of a differencing or validation operation.
* *
* @author Matt Ward * @author Matt Ward
*/ */
public final class Result public class Result
{ {
/** Specifies the type of differences */
public enum Where { ONLY_IN_LEFT, ONLY_IN_RIGHT, IN_BOTH_NO_DIFFERENCE, IN_BOTH_BUT_DIFFERENCE };
public enum Strength { WARN, ERROR }; public enum Strength { WARN, ERROR };
private final Where where; protected final Strength strength;
private final Object left;
private final Object right;
private final String path;
private final Strength strength;
public Result(Where where, Object left, Object right, String path) /**
* @param strength
*/
public Result(Strength strength)
{ {
this(where, left, right, path, null);
}
public Result(Where where, Object left, Object right, String path, Strength strength)
{
this.where = where;
this.left = left;
this.right = right;
this.path = path;
this.strength = (strength != null ? strength : Strength.ERROR); this.strength = (strength != null ? strength : Strength.ERROR);
} }
/**
* @return the where
*/
public Where getWhere()
{
return this.where;
}
/**
* @return the left
*/
public Object getLeft()
{
return this.left;
}
/**
* @return the right
*/
public Object getRight()
{
return this.right;
}
/**
* @return the path
*/
public String getPath()
{
return this.path;
}
/** /**
* @return the strength * @return the strength
*/ */
@ -96,13 +43,4 @@ public final class Result
{ {
return this.strength; return this.strength;
} }
@Override
public String toString()
{
return "Result [where=" + this.where + ", left=" + this.left + ", right=" + this.right
+ ", path=" + this.path + ", strength=" + this.strength + "]";
}
} }

View File

@ -0,0 +1,82 @@
/*
* Copyright (C) 2005-2011 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.util.schemacomp;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.alfresco.util.schemacomp.Difference.Where;
import org.alfresco.util.schemacomp.Result.Strength;
/**
* Collects differences so that tools can report on or respond to differences between database schemas.
*
* @author Matt Ward
*/
public class Results implements Iterable<Difference>
{
private final List<Difference> items = new ArrayList<Difference>();
/** Temporary step during refactor - Where.IN_BOTH_NO_DIFFERENCE will be going altogether */
private boolean reportNonDifferences = false;
/**
* Record a difference between two objects, or specify that an object only appears in either the
* 'left' or 'right' schemas.
*
* @param where The type of difference, see {@link Where}
* @param left Left value, or null if the item appears in the right, but not left schema.
* @param right Right value, or null if the item appears in the left, but not right schema.
* @param strength The Result.Strength of the difference, e.g. WARN or ERROR.
*/
public void add(Where where, DbProperty left, DbProperty right, Strength strength)
{
if (where != Where.IN_BOTH_NO_DIFFERENCE || reportNonDifferences)
{
Difference result = new Difference(where, left, right, strength);
items.add(result);
}
}
public void add(Where where, DbProperty left, DbProperty right)
{
add(where, left, right, null);
}
/**
* Obtain an iterator for the top-level items held in this schema - since this is a hierarchical model,
* deeper items are obtained by navigating through the top-level items.
*/
@Override
public Iterator<Difference> iterator()
{
return items.iterator();
}
/**
* @return How many top-level items are in the schema.
*/
public int size()
{
return items.size();
}
}

View File

@ -29,6 +29,7 @@ import org.junit.runners.Suite;
@RunWith(Suite.class) @RunWith(Suite.class)
@Suite.SuiteClasses( @Suite.SuiteClasses(
{ {
DbPropertyTest.class,
DefaultComparisonUtilsTest.class, DefaultComparisonUtilsTest.class,
SchemaComparatorTest.class, SchemaComparatorTest.class,
ValidatingVisitorTest.class ValidatingVisitorTest.class

View File

@ -47,7 +47,7 @@ public class SchemaComparator
{ {
this.leftSchema = left; this.leftSchema = left;
this.rightSchema = right; this.rightSchema = right;
this.ctx = new DiffContext(dialect, new Differences(), new ArrayList<ValidationResult>()); this.ctx = new DiffContext(dialect, new Results(), new ArrayList<ValidationResult>());
} }
@ -81,7 +81,7 @@ public class SchemaComparator
/** /**
* @return the differences * @return the differences
*/ */
public Differences getDifferences() public Results getDifferences()
{ {
return ctx.getDifferences(); return ctx.getDifferences();
} }

View File

@ -20,7 +20,7 @@ package org.alfresco.util.schemacomp;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.util.Arrays; import java.util.Arrays;
@ -28,10 +28,8 @@ import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import org.alfresco.util.schemacomp.Result.Strength; import org.alfresco.util.schemacomp.Difference.Where;
import org.alfresco.util.schemacomp.Result.Where;
import org.alfresco.util.schemacomp.model.Column; import org.alfresco.util.schemacomp.model.Column;
import org.alfresco.util.schemacomp.model.DbObject;
import org.alfresco.util.schemacomp.model.ForeignKey; import org.alfresco.util.schemacomp.model.ForeignKey;
import org.alfresco.util.schemacomp.model.Index; import org.alfresco.util.schemacomp.model.Index;
import org.alfresco.util.schemacomp.model.PrimaryKey; import org.alfresco.util.schemacomp.model.PrimaryKey;
@ -68,18 +66,18 @@ public class SchemaComparatorTest
public void canPerformDiff() public void canPerformDiff()
{ {
// Left hand side's database objects. // Left hand side's database objects.
left.add(new Table("tbl_no_diff", columns("id NUMBER(10)", "nodeRef VARCHAR2(200)", "name VARCHAR2(150)"), left.add(new Table(left, "tbl_no_diff", columns("id NUMBER(10)", "nodeRef VARCHAR2(200)", "name VARCHAR2(150)"),
pk("pk_tbl_no_diff", "id"), fkeys(fk("fk_tbl_no_diff", "nodeRef", "node", "nodeRef")), pk("pk_tbl_no_diff", "id"), fkeys(fk("fk_tbl_no_diff", "nodeRef", "node", "nodeRef")),
indexes("idx_node id nodeRef"))); indexes("idx_node id nodeRef")));
left.add(table("table_in_left")); left.add(table("table_in_left"));
left.add(new Table("tbl_has_diff_pk", columns("id NUMBER(10)", "nodeRef VARCHAR2(200)"), left.add(new Table(left, "tbl_has_diff_pk", columns("id NUMBER(10)", "nodeRef VARCHAR2(200)"),
pk("pk_is_diff", "id"), fkeys(), indexes())); pk("pk_is_diff", "id"), fkeys(), indexes()));
// Right hand side's database objects. // Right hand side's database objects.
right.add(new Table("tbl_no_diff", columns("id NUMBER(10)", "nodeRef VARCHAR2(200)", "name VARCHAR2(150)"), right.add(new Table(right, "tbl_no_diff", columns("id NUMBER(10)", "nodeRef VARCHAR2(200)", "name VARCHAR2(150)"),
pk("pk_tbl_no_diff", "id"), fkeys(fk("fk_tbl_no_diff", "nodeRef", "node", "nodeRef")), pk("pk_tbl_no_diff", "id"), fkeys(fk("fk_tbl_no_diff", "nodeRef", "node", "nodeRef")),
indexes("idx_node id nodeRef"))); indexes("idx_node id nodeRef")));
right.add(new Table("tbl_has_diff_pk", columns("id NUMBER(10)", "nodeRef VARCHAR2(200)"), right.add(new Table(right, "tbl_has_diff_pk", columns("id NUMBER(10)", "nodeRef VARCHAR2(200)"),
pk("pk_is_diff", "nodeRef"), fkeys(), indexes())); pk("pk_is_diff", "nodeRef"), fkeys(), indexes()));
right.add(table("table_in_right")); right.add(table("table_in_right"));
@ -87,53 +85,57 @@ public class SchemaComparatorTest
comparator = new SchemaComparator(left, right, dialect); comparator = new SchemaComparator(left, right, dialect);
comparator.validateAndCompare(); comparator.validateAndCompare();
// See stdout for diagnostics dump...
dumpDiffs(comparator.getDifferences(), false); dumpDiffs(comparator.getDifferences(), false);
dumpValidation(comparator.getValidationResults()); dumpValidation(comparator.getValidationResults());
Iterator<Result> it = comparator.getDifferences().iterator();
assertHasDifference("left_schema", "left_schema", "right_schema", it.next()); // schema names Results differences = comparator.getDifferences();
assertNoDifference("left_schema.tbl_no_diff", "tbl_no_diff", it.next()); assertEquals(5, differences.size());
assertNoDifference("left_schema.tbl_no_diff.id", "id", it.next());
assertNoDifference("left_schema.tbl_no_diff.id", "NUMBER(10)", it.next());
assertNoDifference("left_schema.tbl_no_diff.id", Boolean.FALSE, it.next()); // nullable
assertNoDifference("left_schema.tbl_no_diff.nodeRef", "nodeRef", it.next());
assertNoDifference("left_schema.tbl_no_diff.nodeRef", "VARCHAR2(200)", it.next());
assertNoDifference("left_schema.tbl_no_diff.nodeRef", Boolean.FALSE, it.next()); // nullable
assertNoDifference("left_schema.tbl_no_diff.name", "name", it.next());
assertNoDifference("left_schema.tbl_no_diff.name", "VARCHAR2(150)", it.next());
assertNoDifference("left_schema.tbl_no_diff.name", Boolean.FALSE, it.next()); // nullable
assertNoDifference("left_schema.tbl_no_diff.pk_tbl_no_diff", "pk_tbl_no_diff", it.next()); // name field
assertNoDifference("left_schema.tbl_no_diff.pk_tbl_no_diff", "id", it.next()); // first (& only) column of list
assertNoDifference("left_schema.tbl_no_diff.fk_tbl_no_diff", "fk_tbl_no_diff", it.next()); // name field
assertNoDifference("left_schema.tbl_no_diff.fk_tbl_no_diff", "nodeRef", it.next()); // localColumn
assertNoDifference("left_schema.tbl_no_diff.fk_tbl_no_diff", "node", it.next()); // targetTable
assertNoDifference("left_schema.tbl_no_diff.fk_tbl_no_diff", "nodeRef", it.next()); // targetColumn
assertNoDifference("left_schema.tbl_no_diff.idx_node", "idx_node", it.next()); // index name
assertNoDifference("left_schema.tbl_no_diff.idx_node", "id", it.next()); // first indexed column
assertNoDifference("left_schema.tbl_no_diff.idx_node", "nodeRef", it.next()); // second indexed column
// TODO: why are diffs for table not flattened out as for index?
assertOnlyInOne("left_schema", Where.ONLY_IN_LEFT, table("table_in_left"), it.next());
assertNoDifference("left_schema.tbl_has_diff_pk", "tbl_has_diff_pk", it.next()); Iterator<Difference> it = differences.iterator();
assertNoDifference("left_schema.tbl_has_diff_pk.id", "id", it.next());
assertNoDifference("left_schema.tbl_has_diff_pk.id", "NUMBER(10)", it.next());
assertNoDifference("left_schema.tbl_has_diff_pk.id", Boolean.FALSE, it.next()); // nullable
assertNoDifference("left_schema.tbl_has_diff_pk.nodeRef", "nodeRef", it.next());
assertNoDifference("left_schema.tbl_has_diff_pk.nodeRef", "VARCHAR2(200)", it.next());
assertNoDifference("left_schema.tbl_has_diff_pk.nodeRef", Boolean.FALSE, it.next()); // nullable
assertNoDifference("left_schema.tbl_has_diff_pk.pk_is_diff", "pk_is_diff", it.next()); // name field
// TODO: surely this should be a diff rather than a ONLY_IN_LEFT plus ONLY_IN_RIGHT? // Schema names are different ("left_schema" vs "right_schema")
// assertHasDifference("left_schema.tbl_has_diff_pk.pk_is_diff", "id", "nodeRef", it.next()); // first (& only) column of list Difference diff = it.next();
assertOnlyInOne("left_schema.tbl_has_diff_pk.pk_is_diff", Where.ONLY_IN_LEFT, "id", it.next()); // first (& only) column of list assertEquals(Where.IN_BOTH_BUT_DIFFERENCE, diff.getWhere());
assertEquals("left_schema.name", diff.getLeft().getPath());
assertEquals("right_schema.name", diff.getRight().getPath());
assertSame(left, diff.getLeft().getDbObject());
assertSame(right, diff.getRight().getDbObject());
assertEquals("name", diff.getLeft().getPropertyName());
assertEquals("left_schema", diff.getLeft().getPropertyValue());
assertEquals("name", diff.getRight().getPropertyName());
assertEquals("right_schema", diff.getRight().getPropertyValue());
// This belong to the pk_is_diff above. // Table table_in_left only appears in the left schema
assertOnlyInOne("left_schema.tbl_has_diff_pk.pk_is_diff", Where.ONLY_IN_RIGHT, "nodeRef", it.next()); // first (& only) column of list diff = it.next();
assertEquals(Where.ONLY_IN_LEFT, diff.getWhere());
assertEquals("left_schema.table_in_left", diff.getLeft().getPath());
assertEquals(null, diff.getRight());
assertEquals(null, diff.getLeft().getPropertyName());
assertEquals(null, diff.getLeft().getPropertyValue());
// Items that are ONLY_IN_RIGHT always come at the end // Table tbl_has_diff_pk has PK of "id" in left and "nodeRef" in right
assertEquals("Should be table with correct name", "tbl_has_diff_pk", ((DbObject) it.next().getRight()).getName()); diff = it.next();
assertOnlyInOne("left_schema", Where.ONLY_IN_RIGHT, table("table_in_right"), it.next()); assertEquals(Where.ONLY_IN_LEFT, diff.getWhere());
assertEquals("left_schema.tbl_has_diff_pk.pk_is_diff.columnNames[0]", diff.getLeft().getPath());
assertEquals("right_schema.tbl_has_diff_pk.pk_is_diff.columnNames", diff.getRight().getPath());
assertEquals("columnNames[0]", diff.getLeft().getPropertyName());
assertEquals("id", diff.getLeft().getPropertyValue());
assertEquals("columnNames", diff.getRight().getPropertyName());
assertEquals(Arrays.asList("nodeRef"), diff.getRight().getPropertyValue());
// Table tbl_has_diff_pk has PK of "id" in left and "nodeRef" in right
diff = it.next();
assertEquals(Where.ONLY_IN_RIGHT, diff.getWhere());
assertEquals("left_schema.tbl_has_diff_pk.pk_is_diff.columnNames", diff.getLeft().getPath());
assertEquals("right_schema.tbl_has_diff_pk.pk_is_diff.columnNames[0]", diff.getRight().getPath());
assertEquals("columnNames", diff.getLeft().getPropertyName());
assertEquals(Arrays.asList("id"), diff.getLeft().getPropertyValue());
assertEquals("columnNames[0]", diff.getRight().getPropertyName());
assertEquals("nodeRef", diff.getRight().getPropertyValue());
// Table table_in_right does not exist in the left schema
} }
@ -146,110 +148,10 @@ public class SchemaComparatorTest
} }
} }
private void dumpDiffs(Results differences, boolean showNonDifferences)
@Test
public void canReportWarnings()
{
// Left hand side's database objects.
left.add(new Table("tbl_example", columns("id NUMBER(10)"), pk("pk_tbl_example", "id"), fkeys(),
indexes("idx_specified_name id")));
// Right hand side's database objects.
right.add(new Table("tbl_example", columns("id NUMBER(10)"), pk("pk_tbl_example", "id"), fkeys(),
indexes("sys_random_idx_name id")));
comparator = new SchemaComparator(left, right, dialect);
comparator.validateAndCompare();
dumpDiffs(comparator.getDifferences(), true);
dumpValidation(comparator.getValidationResults());
Iterator<Result> it = comparator.getDifferences().iterator();
assertHasDifference("left_schema", "left_schema", "right_schema", it.next());
assertNoDifference("left_schema.tbl_example", "tbl_example", it.next());
assertNoDifference("left_schema.tbl_example.id", "id", it.next());
assertNoDifference("left_schema.tbl_example.id", "NUMBER(10)", it.next());
assertNoDifference("left_schema.tbl_example.id", Boolean.FALSE, it.next());
assertNoDifference("left_schema.tbl_example.pk_tbl_example", "pk_tbl_example", it.next());
assertNoDifference("left_schema.tbl_example.pk_tbl_example", "id", it.next());
assertHasWarning(
"left_schema.tbl_example.idx_specified_name",
"idx_specified_name",
"sys_random_idx_name",
it.next());
}
/**
* Assert that the result shows the value to have different values in the left and right items.
*/
private void assertHasDifference(String path, Object leftValue, Object rightValue,
Result result, Strength strength)
{
assertEquals(strength, result.getStrength());
assertEquals(Where.IN_BOTH_BUT_DIFFERENCE, result.getWhere());
assertEquals(path, result.getPath());
assertEquals(leftValue, result.getLeft());
assertEquals(rightValue, result.getRight());
}
/**
* @see #assertHasDifference(String, Object, Object, Result, Strength)
*/
private void assertHasDifference(String path, Object leftValue, Object rightValue, Result result)
{
assertHasDifference(path, leftValue, rightValue, result, Strength.ERROR);
}
/**
* @see #assertHasDifference(String, Object, Object, Result, Strength)
*/
private void assertHasWarning(String path, Object leftValue, Object rightValue, Result result)
{
assertHasDifference(path, leftValue, rightValue, result, Strength.WARN);
}
/**
* Assert that the result shows the value to be present only in either the left or right items.
*/
private void assertOnlyInOne(String path, Where which, Object value, Result result)
{
assertEquals(which, result.getWhere());
assertEquals(path, result.getPath());
if (which == Where.ONLY_IN_LEFT)
{
assertEquals(value, result.getLeft());
assertNull(result.getRight());
}
else if (which == Where.ONLY_IN_RIGHT)
{
assertNull(result.getLeft());
assertEquals(value, result.getRight());
}
else
{
throw new IllegalArgumentException("The 'which' argument should be ONLY_IN_LEFT or ONLY_IN_RIGHT.");
}
}
/**
* Assert that the result shows no differences between the left and right items.
*/
private void assertNoDifference(String path, Object value, Result result)
{
assertEquals(Where.IN_BOTH_NO_DIFFERENCE, result.getWhere());
assertEquals(path, result.getPath());
assertEquals(value, result.getLeft());
assertEquals(value, result.getRight());
}
private void dumpDiffs(Differences differences, boolean showNonDifferences)
{ {
System.out.println("Differences (" + differences.size() + ")"); System.out.println("Differences (" + differences.size() + ")");
for (Result d : differences) for (Difference d : differences)
{ {
if (d.getWhere() != Where.IN_BOTH_NO_DIFFERENCE || showNonDifferences) if (d.getWhere() != Where.IN_BOTH_NO_DIFFERENCE || showNonDifferences)
{ {
@ -260,7 +162,7 @@ public class SchemaComparatorTest
private Table table(String name) private Table table(String name)
{ {
return new Table(name, columns("id NUMBER(10)"), pk("pk_" + name, "id"), fkeys(), indexes()); return new Table(null, name, columns("id NUMBER(10)"), pk("pk_" + name, "id"), fkeys(), indexes());
} }
private Collection<Column> columns(String... colDefs) private Collection<Column> columns(String... colDefs)
@ -271,7 +173,7 @@ public class SchemaComparatorTest
for (int i = 0; i < colDefs.length; i++) for (int i = 0; i < colDefs.length; i++)
{ {
String[] parts = colDefs[i].split(" "); String[] parts = colDefs[i].split(" ");
columns[i] = new Column(parts[0], parts[1], false); columns[i] = new Column(null, parts[0], parts[1], false);
} }
return Arrays.asList(columns); return Arrays.asList(columns);
} }
@ -279,7 +181,7 @@ public class SchemaComparatorTest
private PrimaryKey pk(String name, String... columnNames) private PrimaryKey pk(String name, String... columnNames)
{ {
assertTrue("No columns specified", columnNames.length > 0); assertTrue("No columns specified", columnNames.length > 0);
PrimaryKey pk = new PrimaryKey(name, Arrays.asList(columnNames)); PrimaryKey pk = new PrimaryKey(null, name, Arrays.asList(columnNames));
return pk; return pk;
} }
@ -290,7 +192,7 @@ public class SchemaComparatorTest
private ForeignKey fk(String fkName, String localColumn, String targetTable, String targetColumn) private ForeignKey fk(String fkName, String localColumn, String targetTable, String targetColumn)
{ {
return new ForeignKey(fkName, localColumn, targetTable, targetColumn); return new ForeignKey(null, fkName, localColumn, targetTable, targetColumn);
} }
private Collection<Index> indexes(String... indexDefs) private Collection<Index> indexes(String... indexDefs)
@ -301,7 +203,7 @@ public class SchemaComparatorTest
String[] parts = indexDefs[i].split(" "); String[] parts = indexDefs[i].split(" ");
String name = parts[0]; String name = parts[0];
String[] columns = (String[]) ArrayUtils.subarray(parts, 1, parts.length); String[] columns = (String[]) ArrayUtils.subarray(parts, 1, parts.length);
indexes[i] = new Index(name, Arrays.asList(columns)); indexes[i] = new Index(null, name, Arrays.asList(columns));
} }
return Arrays.asList(indexes); return Arrays.asList(indexes);
} }

View File

@ -19,10 +19,9 @@
package org.alfresco.util.schemacomp; package org.alfresco.util.schemacomp;
import java.util.ArrayList; import static org.junit.Assert.assertSame;
import java.util.Collections;
import javax.faces.validator.Validator; import java.util.ArrayList;
import org.alfresco.util.schemacomp.model.Column; import org.alfresco.util.schemacomp.model.Column;
import org.alfresco.util.schemacomp.model.ForeignKey; import org.alfresco.util.schemacomp.model.ForeignKey;
@ -33,17 +32,14 @@ import org.alfresco.util.schemacomp.model.Sequence;
import org.alfresco.util.schemacomp.model.Table; import org.alfresco.util.schemacomp.model.Table;
import org.alfresco.util.schemacomp.validator.DbValidator; import org.alfresco.util.schemacomp.validator.DbValidator;
import org.alfresco.util.schemacomp.validator.NameValidator; import org.alfresco.util.schemacomp.validator.NameValidator;
import org.alfresco.util.schemacomp.validator.NullValidator;
import org.hibernate.dialect.MySQL5InnoDBDialect; import org.hibernate.dialect.MySQL5InnoDBDialect;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.mockito.Mockito; import org.mockito.Mockito;
import static org.junit.Assert.*;
import static org.mockito.Mockito.validateMockitoUsage;
/** /**
* TODO: comment me! * Tests for the ValidatingVisitor class.
*
* @author Matt Ward * @author Matt Ward
*/ */
public class ValidatingVisitorTest public class ValidatingVisitorTest
@ -54,7 +50,7 @@ public class ValidatingVisitorTest
@Before @Before
public void setUp() throws Exception public void setUp() throws Exception
{ {
ctx = new DiffContext(new MySQL5InnoDBDialect(), new Differences(), new ArrayList<ValidationResult>()); ctx = new DiffContext(new MySQL5InnoDBDialect(), new Results(), new ArrayList<ValidationResult>());
visitor = new ValidatingVisitor(ctx); visitor = new ValidatingVisitor(ctx);
} }
@ -78,7 +74,7 @@ public class ValidatingVisitorTest
public void canValidate() public void canValidate()
{ {
visitor.indexNameValidator = Mockito.mock(NameValidator.class); visitor.indexNameValidator = Mockito.mock(NameValidator.class);
Index index = new Index("index_name", new ArrayList<String>()); Index index = new Index(null, "index_name", new ArrayList<String>());
visitor.visit(index); visitor.visit(index);

View File

@ -19,26 +19,48 @@
package org.alfresco.util.schemacomp; package org.alfresco.util.schemacomp;
/** /**
* TODO: comment me! * Results of a validation operation.
*
* @author Matt Ward * @author Matt Ward
*/ */
public class ValidationResult public class ValidationResult extends Result
{ {
private Object value; private DbProperty dbProperty;
public ValidationResult(DbProperty dbProperty)
{
this(dbProperty, null);
}
public ValidationResult(DbProperty dbProperty, Strength strength)
{
super(strength);
this.dbProperty = dbProperty;
}
/** /**
* @param value * @return the dbProperty that was rejected.
*/ */
public ValidationResult(Object value) public DbProperty getDbProperty()
{ {
this.value = value; return this.dbProperty;
} }
/** /**
* @return the value * @param dbProperty the dbProperty to set
*/
public void setDbProperty(DbProperty dbProperty)
{
this.dbProperty = dbProperty;
}
/**
* @return the value that was rejected.
*/ */
public Object getValue() public Object getValue()
{ {
return this.value; return this.dbProperty.getPropertyValue();
} }
} }

View File

@ -18,17 +18,12 @@
*/ */
package org.alfresco.util.schemacomp.model; package org.alfresco.util.schemacomp.model;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.alfresco.util.schemacomp.ComparisonUtils; import org.alfresco.util.schemacomp.ComparisonUtils;
import org.alfresco.util.schemacomp.DbObjectVisitor; import org.alfresco.util.schemacomp.DbProperty;
import org.alfresco.util.schemacomp.DiffContext;
import org.alfresco.util.schemacomp.Differences;
import org.alfresco.util.schemacomp.Result.Strength;
import org.alfresco.util.schemacomp.DefaultComparisonUtils; import org.alfresco.util.schemacomp.DefaultComparisonUtils;
import org.springframework.util.StringUtils; import org.alfresco.util.schemacomp.DiffContext;
import org.alfresco.util.schemacomp.Result.Strength;
import org.alfresco.util.schemacomp.Results;
/** /**
* Useful base class for many, if not all the {@link DbObject} implementations. * Useful base class for many, if not all the {@link DbObject} implementations.
@ -37,25 +32,22 @@ import org.springframework.util.StringUtils;
*/ */
public abstract class AbstractDbObject implements DbObject public abstract class AbstractDbObject implements DbObject
{ {
private DbObject parent;
private String name; private String name;
/** How differences in the name field should be reported */ /** How differences in the name field should be reported */
private Strength nameStrength = Strength.ERROR; private Strength nameStrength = Strength.ERROR;
protected ComparisonUtils comparisonUtils = new DefaultComparisonUtils(); protected ComparisonUtils comparisonUtils = new DefaultComparisonUtils();
/**
* Default constructor
*/
public AbstractDbObject()
{
}
/** /**
* Instantiate, giving the object a name. * Instantiate, giving the object a parent and a name.
* *
* @param parent
* @param name * @param name
*/ */
public AbstractDbObject(String name) public AbstractDbObject(DbObject parent, String name)
{ {
this.parent = parent;
this.name = name; this.name = name;
} }
@ -152,8 +144,8 @@ public abstract class AbstractDbObject implements DbObject
} }
/** /**
* Provides an implementation of {@link DbObject#diff(DbObject, Differences)}. The template * Provides an implementation of {@link DbObject#diff(DbObject, Results)}. The template
* method {@link #doDiff(DbObject, Differences)} provides the subclass specific diffing logic, * method {@link #doDiff(DbObject, Results)} provides the subclass specific diffing logic,
* whilst this method handles the workflow required in most cases: set the path's prefix that will be * whilst this method handles the workflow required in most cases: set the path's prefix that will be
* used to explain where differences occur; compare the name fields of the two objects; delegate to the * used to explain where differences occur; compare the name fields of the two objects; delegate to the
* subclass specific diffing (if any); remove the last path addition ready for the next object to perform * subclass specific diffing (if any); remove the last path addition ready for the next object to perform
@ -162,19 +154,26 @@ public abstract class AbstractDbObject implements DbObject
@Override @Override
public void diff(DbObject right, DiffContext ctx, Strength strength) public void diff(DbObject right, DiffContext ctx, Strength strength)
{ {
Differences differences = ctx.getDifferences(); DbProperty leftNameProp = new DbProperty(this, "name");
DbProperty rightNameProp = new DbProperty(right, "name");
comparisonUtils.compareSimple(leftNameProp, rightNameProp, ctx, getNameStrength());
if (name != null && StringUtils.hasText(name))
{
differences.pushPath(name);
}
else
{
differences.pushPath("<" + getClass().getSimpleName() + ">");
}
comparisonUtils.compareSimple(name, right.getName(), ctx, getNameStrength());
doDiff(right, ctx, strength); doDiff(right, ctx, strength);
differences.popPath(); }
@Override
public DbObject getParent()
{
return parent;
}
@Override
public void setParent(DbObject parent)
{
this.parent = parent;
} }

View File

@ -26,10 +26,11 @@ import static org.mockito.Mockito.inOrder;
import java.util.ArrayList; import java.util.ArrayList;
import org.alfresco.util.schemacomp.DbObjectVisitor; import org.alfresco.util.schemacomp.DbObjectVisitor;
import org.alfresco.util.schemacomp.DbProperty;
import org.alfresco.util.schemacomp.DiffContext; import org.alfresco.util.schemacomp.DiffContext;
import org.alfresco.util.schemacomp.Differences; import org.alfresco.util.schemacomp.Difference.Where;
import org.alfresco.util.schemacomp.Result.Strength; import org.alfresco.util.schemacomp.Result.Strength;
import org.alfresco.util.schemacomp.Result.Where; import org.alfresco.util.schemacomp.Results;
import org.alfresco.util.schemacomp.ValidationResult; import org.alfresco.util.schemacomp.ValidationResult;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.junit.Before; import org.junit.Before;
@ -48,7 +49,7 @@ import org.mockito.runners.MockitoJUnitRunner;
public class AbstractDbObjectTest public class AbstractDbObjectTest
{ {
private ConcreteDbObject dbObject; private ConcreteDbObject dbObject;
private @Mock Differences differences; private @Mock Results differences;
private DiffContext ctx; private DiffContext ctx;
private @Mock Dialect dialect; private @Mock Dialect dialect;
@ -93,37 +94,52 @@ public class AbstractDbObjectTest
dbObject.diff(otherObject, ctx, Strength.ERROR); dbObject.diff(otherObject, ctx, Strength.ERROR);
InOrder inOrder = inOrder(differences); InOrder inOrder = inOrder(differences);
// The name of the object should be pushed on to the differences path.
inOrder.verify(differences).pushPath("the_object");
// The name of the object should be diffed // The name of the object should be diffed
inOrder.verify(differences).add(Where.IN_BOTH_BUT_DIFFERENCE, "the_object", "the_other_object", Strength.WARN); inOrder.verify(differences).add(
Where.IN_BOTH_BUT_DIFFERENCE,
new DbProperty(dbObject, "name"),
new DbProperty(otherObject, "name"),
Strength.WARN);
// Then the doDiff() method should be processed // Then the doDiff() method should be processed
inOrder.verify(differences).add(Where.IN_BOTH_BUT_DIFFERENCE, "left", "right"); inOrder.verify(differences).add(
// Later, the path should be popped again Where.IN_BOTH_BUT_DIFFERENCE,
inOrder.verify(differences).popPath(); new DbProperty(dbObject, "someProp"),
new DbProperty(otherObject, "someProp"));
} }
/** /**
* Concrete DbObject for testing the AbstractDbObject base class. * Concrete DbObject for testing the AbstractDbObject base class.
*/ */
private static class ConcreteDbObject extends AbstractDbObject public static class ConcreteDbObject extends AbstractDbObject
{ {
private String someProp = "property value";
public ConcreteDbObject(String name) public ConcreteDbObject(String name)
{ {
super(name); super(null, name);
} }
@Override @Override
protected void doDiff(DbObject right, DiffContext ctx, Strength strength) protected void doDiff(DbObject right, DiffContext ctx, Strength strength)
{ {
Differences differences = ctx.getDifferences(); Results differences = ctx.getDifferences();
differences.add(Where.IN_BOTH_BUT_DIFFERENCE, "left", "right"); differences.add(
Where.IN_BOTH_BUT_DIFFERENCE,
new DbProperty(this, "someProp"),
new DbProperty(right, "someProp"));
} }
@Override @Override
public void accept(DbObjectVisitor visitor) public void accept(DbObjectVisitor visitor)
{ {
} }
public String getSomeProp()
{
return this.someProp;
}
} }
} }

View File

@ -19,8 +19,9 @@
package org.alfresco.util.schemacomp.model; package org.alfresco.util.schemacomp.model;
import org.alfresco.util.schemacomp.DbObjectVisitor; import org.alfresco.util.schemacomp.DbObjectVisitor;
import org.alfresco.util.schemacomp.DbProperty;
import org.alfresco.util.schemacomp.DiffContext; import org.alfresco.util.schemacomp.DiffContext;
import org.alfresco.util.schemacomp.Differences; import org.alfresco.util.schemacomp.Results;
import org.alfresco.util.schemacomp.Result.Strength; import org.alfresco.util.schemacomp.Result.Strength;
/** /**
@ -37,13 +38,14 @@ public class Column extends AbstractDbObject
/** /**
* Construct a Column. * Construct a Column.
* *
* @table the parent table
* @param name * @param name
* @param type * @param type
* @param nullable * @param nullable
*/ */
public Column(String name, String type, boolean nullable) public Column(Table table, String name, String type, boolean nullable)
{ {
super(name); super(table, name);
this.type = type; this.type = type;
this.nullable = nullable; this.nullable = nullable;
} }
@ -109,10 +111,16 @@ public class Column extends AbstractDbObject
@Override @Override
protected void doDiff(DbObject right, DiffContext ctx, Strength strength) protected void doDiff(DbObject right, DiffContext ctx, Strength strength)
{ {
Differences differences = ctx.getDifferences(); Results differences = ctx.getDifferences();
Column rightColumn = (Column) right; DbProperty thisTypeProp = new DbProperty(this, "type");
comparisonUtils.compareSimple(type, rightColumn.type, ctx); DbProperty thisNullableProp = new DbProperty(this, "nullable");
comparisonUtils.compareSimple(nullable, rightColumn.nullable, ctx);
Column thatColumn = (Column) right;
DbProperty thatTypeProp = new DbProperty(thatColumn, "type");
DbProperty thatNullableProp = new DbProperty(thatColumn, "nullable");
comparisonUtils.compareSimple(thisTypeProp, thatTypeProp, ctx);
comparisonUtils.compareSimple(thisNullableProp, thatNullableProp, ctx);
} }
@Override @Override

View File

@ -19,6 +19,7 @@
package org.alfresco.util.schemacomp.model; package org.alfresco.util.schemacomp.model;
import org.alfresco.util.schemacomp.DbProperty;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
@ -36,8 +37,8 @@ public class ColumnTest extends DbObjectTestBase<Column>
@Before @Before
public void setUp() throws Exception public void setUp() throws Exception
{ {
thisColumn = new Column("this_column", "VARCHAR2(100)", false); thisColumn = new Column(null, "this_column", "VARCHAR2(100)", false);
thatColumn = new Column("this_column", "NUMBER(10)", true); thatColumn = new Column(null, "that_column", "NUMBER(10)", true);
} }
@Override @Override
@ -55,8 +56,14 @@ public class ColumnTest extends DbObjectTestBase<Column>
@Override @Override
protected void doDiffTests() protected void doDiffTests()
{ {
inOrder.verify(comparisonUtils).compareSimple(thisColumn.getType(), thatColumn.getType(), ctx); DbProperty thisTypeProp = new DbProperty(thisColumn, "type");
inOrder.verify(comparisonUtils).compareSimple(thisColumn.isNullable(), thatColumn.isNullable(), ctx); DbProperty thatTypeProp = new DbProperty(thatColumn, "type");
inOrder.verify(comparisonUtils).compareSimple(thisTypeProp, thatTypeProp, ctx);
DbProperty thisNullableProp = new DbProperty(thisColumn, "nullable");
DbProperty thatNullableProp = new DbProperty(thatColumn, "nullable");
inOrder.verify(comparisonUtils).compareSimple(thisNullableProp, thatNullableProp, ctx);
} }
@Test @Test

View File

@ -20,7 +20,7 @@ package org.alfresco.util.schemacomp.model;
import org.alfresco.util.schemacomp.DbObjectVisitor; import org.alfresco.util.schemacomp.DbObjectVisitor;
import org.alfresco.util.schemacomp.DiffContext; import org.alfresco.util.schemacomp.DiffContext;
import org.alfresco.util.schemacomp.Differences; import org.alfresco.util.schemacomp.Results;
import org.alfresco.util.schemacomp.Result.Strength; import org.alfresco.util.schemacomp.Result.Strength;
/** /**
@ -54,7 +54,7 @@ public interface DbObject
/** /**
* Generate a report of differences between this object ('left') and another object ('right'). * Generate a report of differences between this object ('left') and another object ('right').
* Differences between the left and right objects under inspection are captured in the {@link Differences} * Differences between the left and right objects under inspection are captured in the {@link Results}
* object passed in to this method. * object passed in to this method.
* *
* @param right The object to compare against. * @param right The object to compare against.
@ -70,4 +70,20 @@ public interface DbObject
* @param visitor * @param visitor
*/ */
void accept(DbObjectVisitor visitor); void accept(DbObjectVisitor visitor);
/**
* Get the parent object for which this object is a child. If this is the root object
* then null should be returned.
*
* @return Parent reference or null
*/
DbObject getParent();
/**
* Sets the parent object.
*
* @see #getParent()
* @param parent
*/
void setParent(DbObject parent);
} }

View File

@ -25,8 +25,9 @@ import java.util.List;
import org.alfresco.util.schemacomp.ComparisonUtils; import org.alfresco.util.schemacomp.ComparisonUtils;
import org.alfresco.util.schemacomp.DbObjectVisitor; import org.alfresco.util.schemacomp.DbObjectVisitor;
import org.alfresco.util.schemacomp.DbProperty;
import org.alfresco.util.schemacomp.DiffContext; import org.alfresco.util.schemacomp.DiffContext;
import org.alfresco.util.schemacomp.Differences; import org.alfresco.util.schemacomp.Results;
import org.alfresco.util.schemacomp.Result.Strength; import org.alfresco.util.schemacomp.Result.Strength;
import org.alfresco.util.schemacomp.ValidationResult; import org.alfresco.util.schemacomp.ValidationResult;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
@ -46,7 +47,7 @@ import org.mockito.runners.MockitoJUnitRunner;
public abstract class DbObjectTestBase<T extends AbstractDbObject> public abstract class DbObjectTestBase<T extends AbstractDbObject>
{ {
protected @Mock Dialect dialect; protected @Mock Dialect dialect;
protected @Mock Differences differences; protected @Mock Results differences;
protected DiffContext ctx; protected DiffContext ctx;
protected @Mock ComparisonUtils comparisonUtils; protected @Mock ComparisonUtils comparisonUtils;
protected InOrder inOrder; protected InOrder inOrder;
@ -89,21 +90,15 @@ public abstract class DbObjectTestBase<T extends AbstractDbObject>
// Invoke the method under test // Invoke the method under test
thisObject.diff(thatObject, ctx, Strength.ERROR); thisObject.diff(thatObject, ctx, Strength.ERROR);
// The name of the object should be pushed on to the differences path.
inOrder.verify(differences).pushPath(thisObject.getName());
// The name of the object should be diffed // The name of the object should be diffed
inOrder.verify(comparisonUtils).compareSimple( inOrder.verify(comparisonUtils).compareSimple(
thisObject.getName(), new DbProperty(thisObject, "name"),
thatObject.getName(), new DbProperty(thatObject, "name"),
ctx, ctx,
thisObject.getNameStrength()); thisObject.getNameStrength());
// Then the doDiff() method should be processed... // Then the doDiff() method should be processed...
doDiffTests(); doDiffTests();
// Later, the path should be popped again
inOrder.verify(differences).popPath();
} }
protected abstract void doDiffTests(); protected abstract void doDiffTests();

View File

@ -19,8 +19,9 @@
package org.alfresco.util.schemacomp.model; package org.alfresco.util.schemacomp.model;
import org.alfresco.util.schemacomp.DbObjectVisitor; import org.alfresco.util.schemacomp.DbObjectVisitor;
import org.alfresco.util.schemacomp.DbProperty;
import org.alfresco.util.schemacomp.DiffContext; import org.alfresco.util.schemacomp.DiffContext;
import org.alfresco.util.schemacomp.Differences; import org.alfresco.util.schemacomp.Results;
import org.alfresco.util.schemacomp.Result.Strength; import org.alfresco.util.schemacomp.Result.Strength;
@ -40,14 +41,15 @@ public class ForeignKey extends AbstractDbObject
/** /**
* Constructor. * Constructor.
* *
* @param table the parent table
* @param fkName * @param fkName
* @param localColumn * @param localColumn
* @param targetTable * @param targetTable
* @param targetColumn * @param targetColumn
*/ */
public ForeignKey(String fkName, String localColumn, String targetTable, String targetColumn) public ForeignKey(Table table, String fkName, String localColumn, String targetTable, String targetColumn)
{ {
super(fkName); super(table, fkName);
this.localColumn = localColumn; this.localColumn = localColumn;
this.targetTable = targetTable; this.targetTable = targetTable;
this.targetColumn = targetColumn; this.targetColumn = targetColumn;
@ -141,11 +143,19 @@ public class ForeignKey extends AbstractDbObject
@Override @Override
protected void doDiff(DbObject right, DiffContext ctx, Strength strength) protected void doDiff(DbObject right, DiffContext ctx, Strength strength)
{ {
Differences differences = ctx.getDifferences(); ForeignKey thatFK = (ForeignKey) right;
ForeignKey rightFK = (ForeignKey) right; comparisonUtils.compareSimple(
comparisonUtils.compareSimple(localColumn, rightFK.localColumn, ctx); new DbProperty(this, "localColumn"),
comparisonUtils.compareSimple(targetTable, rightFK.targetTable, ctx); new DbProperty(thatFK, "localColumn"),
comparisonUtils.compareSimple(targetColumn, rightFK.targetColumn, ctx); ctx);
comparisonUtils.compareSimple(
new DbProperty(this, "targetTable"),
new DbProperty(thatFK, "targetTable"),
ctx);
comparisonUtils.compareSimple(
new DbProperty(this, "targetColumn"),
new DbProperty(thatFK, "targetColumn"),
ctx);
} }
@Override @Override

View File

@ -21,6 +21,7 @@ package org.alfresco.util.schemacomp.model;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import org.alfresco.util.schemacomp.DbProperty;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -37,8 +38,8 @@ public class ForeignKeyTest extends DbObjectTestBase<ForeignKey>
@Before @Before
public void setUp() throws Exception public void setUp() throws Exception
{ {
thisFK = new ForeignKey("this_fk", "local_col", "target_table", "target_col"); thisFK = new ForeignKey(null, "this_fk", "local_col", "target_table", "target_col");
thatFK = new ForeignKey("that_fk", "local_col", "target_table", "target_col"); thatFK = new ForeignKey(null, "that_fk", "local_col", "target_table", "target_col");
} }
@ -59,9 +60,18 @@ public class ForeignKeyTest extends DbObjectTestBase<ForeignKey>
@Override @Override
protected void doDiffTests() protected void doDiffTests()
{ {
inOrder.verify(comparisonUtils).compareSimple(thisFK.getLocalColumn(), thatFK.getLocalColumn(), ctx); inOrder.verify(comparisonUtils).compareSimple(
inOrder.verify(comparisonUtils).compareSimple(thisFK.getTargetTable(), thatFK.getTargetTable(), ctx); new DbProperty(thisFK, "localColumn"),
inOrder.verify(comparisonUtils).compareSimple(thisFK.getTargetColumn(), thatFK.getTargetColumn(), ctx); new DbProperty(thatFK, "localColumn"),
ctx);
inOrder.verify(comparisonUtils).compareSimple(
new DbProperty(thisFK, "targetTable"),
new DbProperty(thatFK, "targetTable"),
ctx);
inOrder.verify(comparisonUtils).compareSimple(
new DbProperty(thisFK, "targetColumn"),
new DbProperty(thatFK, "targetColumn"),
ctx);
} }
@Test @Test

View File

@ -21,8 +21,8 @@ package org.alfresco.util.schemacomp.model;
import java.util.List; import java.util.List;
import org.alfresco.util.schemacomp.DbObjectVisitor; import org.alfresco.util.schemacomp.DbObjectVisitor;
import org.alfresco.util.schemacomp.DbProperty;
import org.alfresco.util.schemacomp.DiffContext; import org.alfresco.util.schemacomp.DiffContext;
import org.alfresco.util.schemacomp.Differences;
import org.alfresco.util.schemacomp.Result.Strength; import org.alfresco.util.schemacomp.Result.Strength;
/** /**
@ -36,11 +36,12 @@ public class Index extends AbstractDbObject
/** /**
* @param table the parent table
* @param columnNames * @param columnNames
*/ */
public Index(String name, List<String> columnNames) public Index(Table table, String name, List<String> columnNames)
{ {
super(name); super(table, name);
this.columnNames = columnNames; this.columnNames = columnNames;
setNameStrength(Strength.WARN); setNameStrength(Strength.WARN);
} }
@ -112,9 +113,12 @@ public class Index extends AbstractDbObject
@Override @Override
protected void doDiff(DbObject right, DiffContext ctx, Strength strength) protected void doDiff(DbObject right, DiffContext ctx, Strength strength)
{ {
Differences differences = ctx.getDifferences();
Index rightIndex = (Index) right; Index rightIndex = (Index) right;
comparisonUtils.compareSimpleCollections(columnNames, rightIndex.columnNames, ctx, strength); comparisonUtils.compareSimpleCollections(
new DbProperty(this, "columnNames"),
new DbProperty(rightIndex, "columnNames"),
ctx,
strength);
} }

View File

@ -20,6 +20,7 @@ package org.alfresco.util.schemacomp.model;
import java.util.Arrays; import java.util.Arrays;
import org.alfresco.util.schemacomp.DbProperty;
import org.alfresco.util.schemacomp.Result.Strength; import org.alfresco.util.schemacomp.Result.Strength;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -39,8 +40,8 @@ public class IndexTest extends DbObjectTestBase<Index>
@Before @Before
public void setUp() public void setUp()
{ {
thisIndex = new Index("this_index", Arrays.asList("id", "name", "age")); thisIndex = new Index(null, "this_index", Arrays.asList("id", "name", "age"));
thatIndex = new Index("that_index", Arrays.asList("a", "b")); thatIndex = new Index(null, "that_index", Arrays.asList("a", "b"));
} }
@Override @Override
@ -59,8 +60,8 @@ public class IndexTest extends DbObjectTestBase<Index>
protected void doDiffTests() protected void doDiffTests()
{ {
inOrder.verify(comparisonUtils).compareSimpleCollections( inOrder.verify(comparisonUtils).compareSimpleCollections(
thisIndex.getColumnNames(), new DbProperty(thisIndex, "columnNames"),
thatIndex.getColumnNames(), new DbProperty(thatIndex, "columnNames"),
ctx, ctx,
Strength.ERROR); Strength.ERROR);
} }
@ -77,19 +78,19 @@ public class IndexTest extends DbObjectTestBase<Index>
public void sameAs() public void sameAs()
{ {
assertTrue("Indexes should be logically the same.", assertTrue("Indexes should be logically the same.",
thisIndex.sameAs(new Index("this_index", Arrays.asList("id", "name", "age")))); thisIndex.sameAs(new Index(null, "this_index", Arrays.asList("id", "name", "age"))));
assertTrue("Indexes should be logically the same, despite different names (as same column order)", assertTrue("Indexes should be logically the same, despite different names (as same column order)",
thisIndex.sameAs(new Index("different_name", Arrays.asList("id", "name", "age")))); thisIndex.sameAs(new Index(null, "different_name", Arrays.asList("id", "name", "age"))));
assertTrue("Indexes should be identified as the same despite different column order (as same name).", assertTrue("Indexes should be identified as the same despite different column order (as same name).",
thisIndex.sameAs(new Index("this_index", Arrays.asList("name", "id", "age")))); thisIndex.sameAs(new Index(null, "this_index", Arrays.asList("name", "id", "age"))));
assertFalse("Indexes should be identified different (different name and column order)", assertFalse("Indexes should be identified different (different name and column order)",
thisIndex.sameAs(new Index("different_name", Arrays.asList("name", "id", "age")))); thisIndex.sameAs(new Index(null, "different_name", Arrays.asList("name", "id", "age"))));
assertFalse("Indexes should be identified different (different name & different columns)", assertFalse("Indexes should be identified different (different name & different columns)",
thisIndex.sameAs(new Index("different_name", Arrays.asList("node_ref", "url")))); thisIndex.sameAs(new Index(null, "different_name", Arrays.asList("node_ref", "url"))));
} }

View File

@ -21,8 +21,8 @@ package org.alfresco.util.schemacomp.model;
import java.util.List; import java.util.List;
import org.alfresco.util.schemacomp.DbObjectVisitor; import org.alfresco.util.schemacomp.DbObjectVisitor;
import org.alfresco.util.schemacomp.DbProperty;
import org.alfresco.util.schemacomp.DiffContext; import org.alfresco.util.schemacomp.DiffContext;
import org.alfresco.util.schemacomp.Differences;
import org.alfresco.util.schemacomp.Result.Strength; import org.alfresco.util.schemacomp.Result.Strength;
/** /**
@ -37,12 +37,13 @@ public class PrimaryKey extends AbstractDbObject
/** /**
* Constructor * Constructor
* @param table the parent table
* @param name * @param name
* @param columnNames * @param columnNames
*/ */
public PrimaryKey(String name, List<String> columnNames) public PrimaryKey(Table table, String name, List<String> columnNames)
{ {
super(name); super(table, name);
this.columnNames = columnNames; this.columnNames = columnNames;
} }
@ -89,9 +90,12 @@ public class PrimaryKey extends AbstractDbObject
@Override @Override
protected void doDiff(DbObject right, DiffContext ctx, Strength strength) protected void doDiff(DbObject right, DiffContext ctx, Strength strength)
{ {
Differences differences = ctx.getDifferences();
PrimaryKey rightPK = (PrimaryKey) right; PrimaryKey rightPK = (PrimaryKey) right;
comparisonUtils.compareSimpleCollections(columnNames, rightPK.columnNames, ctx, strength); comparisonUtils.compareSimpleCollections(
new DbProperty(this, "columnNames"),
new DbProperty(rightPK, "columnNames"),
ctx,
strength);
} }
@Override @Override

View File

@ -22,6 +22,7 @@ import static org.mockito.Mockito.verify;
import java.util.Arrays; import java.util.Arrays;
import org.alfresco.util.schemacomp.DbProperty;
import org.alfresco.util.schemacomp.Result.Strength; import org.alfresco.util.schemacomp.Result.Strength;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -40,8 +41,8 @@ public class PrimaryKeyTest extends DbObjectTestBase<PrimaryKey>
@Before @Before
public void setUp() public void setUp()
{ {
thisPK = new PrimaryKey("this_pk", Arrays.asList("id", "name", "age")); thisPK = new PrimaryKey(null, "this_pk", Arrays.asList("id", "name", "age"));
thatPK = new PrimaryKey("that_pk", Arrays.asList("a", "b")); thatPK = new PrimaryKey(null, "that_pk", Arrays.asList("a", "b"));
} }
@Override @Override
@ -60,8 +61,8 @@ public class PrimaryKeyTest extends DbObjectTestBase<PrimaryKey>
protected void doDiffTests() protected void doDiffTests()
{ {
inOrder.verify(comparisonUtils).compareSimpleCollections( inOrder.verify(comparisonUtils).compareSimpleCollections(
thisPK.getColumnNames(), new DbProperty(thisPK, "columnNames"),
thatPK.getColumnNames(), new DbProperty(thatPK, "columnNames"),
ctx, ctx,
Strength.ERROR); Strength.ERROR);
} }

View File

@ -24,7 +24,7 @@ import java.util.List;
import org.alfresco.util.schemacomp.DbObjectVisitor; import org.alfresco.util.schemacomp.DbObjectVisitor;
import org.alfresco.util.schemacomp.DiffContext; import org.alfresco.util.schemacomp.DiffContext;
import org.alfresco.util.schemacomp.Differences; import org.alfresco.util.schemacomp.Results;
import org.alfresco.util.schemacomp.Result.Strength; import org.alfresco.util.schemacomp.Result.Strength;
/** /**
@ -43,11 +43,18 @@ public class Schema extends AbstractDbObject implements Iterable<DbObject>
*/ */
public Schema(String name) public Schema(String name)
{ {
super(name); super(null, name);
} }
/**
* Add an object to this schema - this method will set this schema
* as the object's parent.
*
* @param dbObject
*/
public void add(DbObject dbObject) public void add(DbObject dbObject)
{ {
dbObject.setParent(this);
objects.add(dbObject); objects.add(dbObject);
} }
@ -94,7 +101,6 @@ public class Schema extends AbstractDbObject implements Iterable<DbObject>
@Override @Override
protected void doDiff(DbObject right, DiffContext ctx, Strength strength) protected void doDiff(DbObject right, DiffContext ctx, Strength strength)
{ {
Differences differences = ctx.getDifferences();
Schema rightSchema = (Schema) right; Schema rightSchema = (Schema) right;
comparisonUtils.compareCollections(objects, rightSchema.objects, ctx); comparisonUtils.compareCollections(objects, rightSchema.objects, ctx);
} }

View File

@ -28,9 +28,9 @@ import org.alfresco.util.schemacomp.DbObjectVisitor;
*/ */
public class Sequence extends AbstractDbObject public class Sequence extends AbstractDbObject
{ {
public Sequence(String name) public Sequence(DbObject parent, String name)
{ {
super(name); super(parent, name);
} }
@Override @Override

View File

@ -21,7 +21,6 @@ package org.alfresco.util.schemacomp.model;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import org.junit.Before; import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
/** /**
@ -36,8 +35,8 @@ public class SequenceTest extends DbObjectTestBase<Sequence>
@Before @Before
public void setUp() public void setUp()
{ {
thisSequence = new Sequence("this_sequence"); thisSequence = new Sequence(null, "this_sequence");
thatSequence = new Sequence("that_sequence"); thatSequence = new Sequence(null, "that_sequence");
} }
@Test @Test

View File

@ -24,7 +24,6 @@ import java.util.List;
import org.alfresco.util.schemacomp.DbObjectVisitor; import org.alfresco.util.schemacomp.DbObjectVisitor;
import org.alfresco.util.schemacomp.DiffContext; import org.alfresco.util.schemacomp.DiffContext;
import org.alfresco.util.schemacomp.Differences;
import org.alfresco.util.schemacomp.Result.Strength; import org.alfresco.util.schemacomp.Result.Strength;
/** /**
@ -34,28 +33,29 @@ import org.alfresco.util.schemacomp.Result.Strength;
*/ */
public class Table extends AbstractDbObject public class Table extends AbstractDbObject
{ {
private List<Column> columns = new ArrayList<Column>(); private final List<Column> columns = new ArrayList<Column>();
private PrimaryKey primaryKey; private PrimaryKey primaryKey;
private List<ForeignKey> foreignKeys = new ArrayList<ForeignKey>(); private final List<ForeignKey> foreignKeys = new ArrayList<ForeignKey>();
private List<Index> indexes = new ArrayList<Index>(); private final List<Index> indexes = new ArrayList<Index>();
public Table(String name, Collection<Column> columns, PrimaryKey primaryKey, public Table(Schema parentSchema, String name, Collection<Column> columns, PrimaryKey primaryKey,
Collection<ForeignKey> foreignKeys, Collection<Index> indexes) Collection<ForeignKey> foreignKeys, Collection<Index> indexes)
{ {
super(name); super(parentSchema, name);
if (columns != null) if (columns != null)
{ {
this.columns.addAll(columns); setColumns(columns);
} }
primaryKey.setParent(this);
this.primaryKey = primaryKey; this.primaryKey = primaryKey;
if (foreignKeys != null) if (foreignKeys != null)
{ {
this.foreignKeys.addAll(foreignKeys); setForeignKeys(foreignKeys);
} }
if (indexes != null) if (indexes != null)
{ {
this.indexes.addAll(indexes); setIndexes(indexes);
} }
} }
@ -72,9 +72,15 @@ public class Table extends AbstractDbObject
/** /**
* @param columns the columns to set * @param columns the columns to set
*/ */
public void setColumns(List<Column> columns) public void setColumns(Collection<Column> columns)
{ {
this.columns = columns; this.columns.clear();
this.columns.addAll(columns);
for (Column column : columns)
{
column.setParent(this);
}
} }
@ -92,6 +98,7 @@ public class Table extends AbstractDbObject
*/ */
public void setPrimaryKey(PrimaryKey primaryKey) public void setPrimaryKey(PrimaryKey primaryKey)
{ {
primaryKey.setParent(this);
this.primaryKey = primaryKey; this.primaryKey = primaryKey;
} }
@ -108,9 +115,15 @@ public class Table extends AbstractDbObject
/** /**
* @param foreignKeys the foreignKeys to set * @param foreignKeys the foreignKeys to set
*/ */
public void setForeignKeys(List<ForeignKey> foreignKeys) public void setForeignKeys(Collection<ForeignKey> foreignKeys)
{ {
this.foreignKeys = foreignKeys; this.foreignKeys.clear();
this.foreignKeys.addAll(foreignKeys);
for (ForeignKey fk : foreignKeys)
{
fk.setParent(this);
}
} }
@ -126,9 +139,15 @@ public class Table extends AbstractDbObject
/** /**
* @param indexes the indexes to set * @param indexes the indexes to set
*/ */
public void setIndexes(List<Index> indexes) public void setIndexes(Collection<Index> indexes)
{ {
this.indexes = indexes; this.indexes.clear();
this.indexes.addAll(indexes);
for (Index index : indexes)
{
index.setParent(this);
}
} }
@ -179,7 +198,6 @@ public class Table extends AbstractDbObject
@Override @Override
protected void doDiff(DbObject other, DiffContext ctx, Strength strength) protected void doDiff(DbObject other, DiffContext ctx, Strength strength)
{ {
Differences differences = ctx.getDifferences();
Table rightTable = (Table) other; Table rightTable = (Table) other;
comparisonUtils.compareCollections(columns, rightTable.columns, ctx); comparisonUtils.compareCollections(columns, rightTable.columns, ctx);
primaryKey.diff(rightTable.primaryKey, ctx, strength); primaryKey.diff(rightTable.primaryKey, ctx, strength);

View File

@ -19,17 +19,12 @@
package org.alfresco.util.schemacomp.model; package org.alfresco.util.schemacomp.model;
import static java.util.Arrays.asList;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.alfresco.util.schemacomp.Result.Strength; import org.alfresco.util.schemacomp.Result.Strength;
import org.apache.poi.ss.formula.functions.Columns;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -56,26 +51,11 @@ public class TableTest extends DbObjectTestBase<Table>
@Before @Before
public void setUp() throws Exception public void setUp() throws Exception
{ {
/*columns = asList(
new Column("columnA", "VARCHAR2(50)", false),
new Column("columnB", "VARCHAR2(100)", false),
new Column("columnC", "VARCHAR2(200)", true));
foreignKeys = asList(new ForeignKey("fk", "localcolumn", "targettable", "targetcolumn"));
indexes = asList(new Index("an_index", asList("columnA", "columnC")));
table = new Table("the_table", columns, primaryKey, foreignKeys, indexes);
otherTable = new Table("the_other_table", columns, primaryKey, foreignKeys, indexes);*/
columns = listOfMocks(Column.class, 3); columns = listOfMocks(Column.class, 3);
foreignKeys = listOfMocks(ForeignKey.class, 1); foreignKeys = listOfMocks(ForeignKey.class, 1);
indexes = listOfMocks(Index.class, 1); indexes = listOfMocks(Index.class, 1);
table = new Table(null, "the_table", columns, primaryKey, foreignKeys, indexes);
table = new Table("the_table", columns, primaryKey, foreignKeys, indexes); otherTable = new Table(null, "the_other_table", columns, primaryKey, foreignKeys, indexes);
otherTable = new Table("the_other_table", columns, primaryKey, foreignKeys, indexes);
} }

View File

@ -22,7 +22,9 @@ import org.alfresco.util.schemacomp.DiffContext;
import org.alfresco.util.schemacomp.model.DbObject; import org.alfresco.util.schemacomp.model.DbObject;
/** /**
* TODO: comment me! * DbObject validators must implement this interface. DbValidator instances
* are used by the ValidatingVisitor class.
*
* @author Matt Ward * @author Matt Ward
*/ */
public interface DbValidator public interface DbValidator

View File

@ -22,6 +22,7 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.alfresco.util.schemacomp.DbProperty;
import org.alfresco.util.schemacomp.DiffContext; import org.alfresco.util.schemacomp.DiffContext;
import org.alfresco.util.schemacomp.ValidationResult; import org.alfresco.util.schemacomp.ValidationResult;
import org.alfresco.util.schemacomp.model.DbObject; import org.alfresco.util.schemacomp.model.DbObject;
@ -47,7 +48,7 @@ public class NameValidator implements DbValidator
Pattern pattern = namePatterns.get(ctx.getDialect().getClass()); Pattern pattern = namePatterns.get(ctx.getDialect().getClass());
ValidationResult result = new ValidationResult(name); ValidationResult result = new ValidationResult(new DbProperty(dbo, "name"));
if (pattern != null && !pattern.matcher(name).matches()) if (pattern != null && !pattern.matcher(name).matches())
{ {

View File

@ -19,15 +19,16 @@
package org.alfresco.util.schemacomp.validator; package org.alfresco.util.schemacomp.validator;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.alfresco.util.schemacomp.DiffContext; import org.alfresco.util.schemacomp.DiffContext;
import org.alfresco.util.schemacomp.Differences; import org.alfresco.util.schemacomp.Results;
import org.alfresco.util.schemacomp.ValidationResult; import org.alfresco.util.schemacomp.ValidationResult;
import org.alfresco.util.schemacomp.model.DbObject; import org.alfresco.util.schemacomp.model.DbObject;
import org.alfresco.util.schemacomp.model.Index; import org.alfresco.util.schemacomp.model.Index;
@ -36,8 +37,6 @@ import org.hibernate.dialect.Oracle10gDialect;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.*;
/** /**
* Tests for the NameValidator class. * Tests for the NameValidator class.
* *
@ -54,7 +53,7 @@ public class NameValidatorTest
{ {
validator = new NameValidator(); validator = new NameValidator();
validationResults = new ArrayList<ValidationResult>(); validationResults = new ArrayList<ValidationResult>();
ctx = new DiffContext(new Oracle10gDialect(), new Differences(), validationResults); ctx = new DiffContext(new Oracle10gDialect(), new Results(), validationResults);
} }
@Test @Test
@ -88,6 +87,6 @@ public class NameValidatorTest
private DbObject indexForName(String name) private DbObject indexForName(String name)
{ {
return new Index(name, new ArrayList<String>()); return new Index(null, name, new ArrayList<String>());
} }
} }

View File

@ -22,7 +22,8 @@ import org.alfresco.util.schemacomp.DiffContext;
import org.alfresco.util.schemacomp.model.DbObject; import org.alfresco.util.schemacomp.model.DbObject;
/** /**
* TODO: comment me! * A 'do nothing' validator
*
* @author Matt Ward * @author Matt Ward
*/ */
public class NullValidator implements DbValidator public class NullValidator implements DbValidator