diff --git a/source/java/org/alfresco/util/schemacomp/ComparisonUtils.java b/source/java/org/alfresco/util/schemacomp/ComparisonUtils.java new file mode 100644 index 0000000000..189dac3a9a --- /dev/null +++ b/source/java/org/alfresco/util/schemacomp/ComparisonUtils.java @@ -0,0 +1,83 @@ +/* + * 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 . + */ + +package org.alfresco.util.schemacomp; + +import java.util.Collection; + +import org.alfresco.util.schemacomp.Result.Strength; +import org.alfresco.util.schemacomp.model.DbObject; + +/** + * Utilities for comparing data structures in the context of comparing two database schemas. + * + * @author Matt Ward + */ +public interface ComparisonUtils +{ + /** + * @param objToFind + * @return + */ + DbObject findSameObjectAs(Collection objects, final DbObject objToFind); + + void compareSimpleCollections(Collection leftCollection, + Collection rightCollection, Differences differences, + Strength strength); + + /** + * Compare collections, reporting differences using the default {@link Result.Strength} + * + * @see #compareCollections(Collection, Collection, Differences, Strength) + */ + void compareCollections(Collection leftCollection, + Collection rightCollection, Differences differences); + + /** + * Compare collections of {@link DbObject}s using their {@link DbObject#diff(DbObject, Differences)} method. + * Differences are reported using the specified {@link Result.Strength}. + * + * @param leftCollection + * @param rightCollection + * @param differences + * @param strength + */ + void compareCollections(Collection leftCollection, + Collection rightCollection, Differences differences, + Strength strength); + + /** + * Compare two simple objects. Differences are reported using the default Result.Strength. + * + * @see #compareSimple(Object, Object, Differences, Strength) + */ + void compareSimple(Object left, Object right, Differences differences); + + /** + * Compare two 'simple' (i.e. non-{@link DbObject} objects) using their {@link Object#equals(Object)} method + * to decide if there is a difference. Differences are reported using the Result.Strength specified. + * + * @param left + * @param right + * @param differences + * @param strength + */ + void compareSimple(Object left, Object right, Differences differences, Strength strength); + +} \ No newline at end of file diff --git a/source/java/org/alfresco/util/schemacomp/DefaultComparisonUtils.java b/source/java/org/alfresco/util/schemacomp/DefaultComparisonUtils.java new file mode 100644 index 0000000000..3c48e649e7 --- /dev/null +++ b/source/java/org/alfresco/util/schemacomp/DefaultComparisonUtils.java @@ -0,0 +1,197 @@ +/* + * 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 . + */ + +package org.alfresco.util.schemacomp; + +import java.util.Collection; + +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.collections.CollectionUtils; +import org.apache.commons.collections.Predicate; + +/** + * A collection of utility methods for determining differences between two database schemas. + * + * @author Matt Ward + */ +public class DefaultComparisonUtils implements ComparisonUtils +{ + /** + * @param objToFind + * @return + */ + @Override + public DbObject findSameObjectAs(Collection objects, final DbObject objToFind) + { + return (DbObject) CollectionUtils.find(objects, new Predicate() + { + @Override + public boolean evaluate(Object o) + { + DbObject object = (DbObject) o; + return object.sameAs(objToFind); + } + }); + } + + + @Override + public void compareSimpleCollections(Collection leftCollection, + Collection rightCollection, Differences differences, Strength strength) + { + for (Object leftObj : leftCollection) + { + if (rightCollection.contains(leftObj)) + { + // 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 + // 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?) + differences.add(Where.IN_BOTH_NO_DIFFERENCE, leftObj, leftObj, strength); + } + else + { + // No equivalent object in the right hand collection. + differences.add(Where.ONLY_IN_LEFT, leftObj, null, strength); + } + } + + // Identify objects in the right collection but not the left + for (Object rightObj : rightCollection) + { + if (!leftCollection.contains(rightObj)) + { + // No equivalent object in the left hand collection. + differences.add(Where.ONLY_IN_RIGHT, null, rightObj, strength); + } + } + } + + /** + * Compare collections, reporting differences using the default {@link Result.Strength} + * + * @see #compareCollections(Collection, Collection, Differences, Strength) + */ + @Override + public void compareCollections(Collection leftCollection, + Collection rightCollection, Differences differences) + { + compareCollections(leftCollection, rightCollection, differences, null); + } + + /** + * Compare collections of {@link DbObject}s using their {@link DbObject#diff(DbObject, Differences)} method. + * Differences are reported using the specified {@link Result.Strength}. + * + * @param leftCollection + * @param rightCollection + * @param differences + * @param strength + */ + @Override + public void compareCollections(Collection leftCollection, + Collection rightCollection, Differences differences, Strength strength) + { + for (DbObject leftObj : leftCollection) + { + DbObject rightObj = findSameObjectAs(rightCollection, leftObj); + + if (rightObj != null) + { + // There is an equivalent object in the right hand collection as + // in the left. + leftObj.diff(rightObj, differences, strength); + } + else + { + // No equivalent object in the right hand collection. + differences.add(Where.ONLY_IN_LEFT, leftObj, null, strength); + } + } + + // Identify objects in the right collection but not the left + for (DbObject rightObj : rightCollection) + { + if (!leftCollection.contains(rightObj)) + { + // No equivalent object in the left hand collection. + differences.add(Where.ONLY_IN_RIGHT, null, rightObj, strength); + } + } + } + + /** + * Compare two simple objects. Differences are reported using the default Result.Strength. + * + * @see #compareSimple(Object, Object, Differences, Strength) + */ + @Override + public void compareSimple(Object left, Object right, Differences differences) + { + compareSimple(left, right, differences, null); + } + + /** + * Compare two 'simple' (i.e. non-{@link DbObject} objects) using their {@link Object#equals(Object)} method + * to decide if there is a difference. Differences are reported using the Result.Strength specified. + * + * @param left + * @param right + * @param differences + * @param strength + */ + @Override + public void compareSimple(Object left, Object right, Differences differences, Strength strength) + { + + Where where = null; + + if (left == right) + { + // Same object, or both nulls + where = Where.IN_BOTH_NO_DIFFERENCE; + } + else if (left == null) + { + // right can't be null, or left == right would have been true + where = Where.ONLY_IN_RIGHT; + } + else if (right == null) + { + // left can't be null, or left == right would have been true + where = Where.ONLY_IN_LEFT; + } + else + { + // neither are null + if (left.equals(right)) + { + where = Where.IN_BOTH_NO_DIFFERENCE; + } + else + { + where = Where.IN_BOTH_BUT_DIFFERENCE; + } + } + + differences.add(where, left, right, strength); + } +} diff --git a/source/java/org/alfresco/util/schemacomp/DefaultComparisonUtilsTest.java b/source/java/org/alfresco/util/schemacomp/DefaultComparisonUtilsTest.java new file mode 100644 index 0000000000..b712b3ee7d --- /dev/null +++ b/source/java/org/alfresco/util/schemacomp/DefaultComparisonUtilsTest.java @@ -0,0 +1,193 @@ +/* + * 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 . + */ +package org.alfresco.util.schemacomp; + + +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.alfresco.util.schemacomp.Result.Strength; +import org.alfresco.util.schemacomp.Result.Where; +import org.alfresco.util.schemacomp.model.DbObject; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +/** + * Tests for the SchemaUtils class. + * + * @author Matt Ward + */ +@RunWith(MockitoJUnitRunner.class) +public class DefaultComparisonUtilsTest +{ + private @Mock Differences differences; + private DefaultComparisonUtils comparisonUtils; + + @Before + public void setUp() + { + comparisonUtils = new DefaultComparisonUtils(); + } + + @Test + public void compareSimple() + { + comparisonUtils.compareSimple(null, null, differences, Strength.ERROR); + verify(differences).add(Where.IN_BOTH_NO_DIFFERENCE, null, null, Strength.ERROR); + + comparisonUtils.compareSimple("not_null_string", "not_null_string", differences, Strength.ERROR); + verify(differences).add(Where.IN_BOTH_NO_DIFFERENCE, "not_null_string", "not_null_string", Strength.ERROR); + + comparisonUtils.compareSimple("left", "right", differences, Strength.ERROR); + verify(differences).add(Where.IN_BOTH_BUT_DIFFERENCE, "left", "right", Strength.ERROR); + + comparisonUtils.compareSimple("left", null, differences, Strength.ERROR); + verify(differences).add(Where.ONLY_IN_LEFT, "left", null, Strength.ERROR); + + comparisonUtils.compareSimple(null, "right", differences, Strength.ERROR); + verify(differences).add(Where.ONLY_IN_RIGHT, null, "right", Strength.ERROR); + } + + + @Test + public void compareCollections() + { + DbObject db1 = mock(DbObject.class); + when(db1.sameAs(db1)).thenReturn(true); + DbObject db2 = mock(DbObject.class); // only in left + when(db2.sameAs(db2)).thenReturn(true); + DbObject db3 = mock(DbObject.class); // only in right + when(db3.sameAs(db3)).thenReturn(true); + DbObject db4 = mock(DbObject.class); + when(db4.sameAs(db4)).thenReturn(true); + + Collection left = new ArrayList(); + Collections.addAll(left, db1, db2, db4); + + Collection right = new ArrayList(); + Collections.addAll(right, db1, db3, db4); + + comparisonUtils.compareCollections(left, right, differences, Strength.ERROR); + + // Objects in both are asked for their differences + verify(db1).diff(db1, differences, Strength.ERROR); + verify(db4).diff(db4, differences, Strength.ERROR); + + // 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_RIGHT, null, db3, Strength.ERROR); + } + + + @Test + public void compareSimpleCollections() + { + Collection leftCollection = new ArrayList(); + leftCollection.add(123); + leftCollection.add("both"); + Collection subCollectionLeft = new ArrayList(); + subCollectionLeft.add(3); + subCollectionLeft.add("my string"); + subCollectionLeft.add(10); + subCollectionLeft.add("another"); + leftCollection.add(subCollectionLeft); + leftCollection.add(456); + leftCollection.add("left only"); + + Collection rightCollection = new ArrayList(); + rightCollection.add(123); + rightCollection.add(789); + Collection subCollectionRight = new ArrayList(subCollectionLeft); + rightCollection.add(subCollectionRight); + rightCollection.add("right only"); + rightCollection.add("both"); + rightCollection.add("one more right only"); + + comparisonUtils.compareSimpleCollections(leftCollection, rightCollection, differences, 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(Where.ONLY_IN_RIGHT, null, "right only", Strength.WARN); + verify(differences).add(Where.ONLY_IN_RIGHT, null, "one more right only", Strength.WARN); + } + + + @Test + public void findSameObjectAsSuccessfulFind() + { + // Make a list of mock DbOjbect objects to test against + int numObjects = 20; + List dbObjects = createMockDbObjects(numObjects); + + // The reference that will be used to look for one 'the same' in the collection. + DbObject toFind = mock(DbObject.class); + + // For all other objects sameAs() will return false + DbObject objShouldBeFound = dbObjects.get(12); + when(objShouldBeFound.sameAs(toFind)).thenReturn(true); + + DbObject found = comparisonUtils.findSameObjectAs(dbObjects, toFind); + + assertSame("Found the wrong DbObject", objShouldBeFound, found); + } + + + @Test + public void findSameObjectAsNotFound() + { + // Make a list of mock DbOjbect objects to test against + int numObjects = 20; + List dbObjects = createMockDbObjects(numObjects); + + // The reference that will be used to look for one 'the same' in the collection. + DbObject toFind = mock(DbObject.class); + + DbObject found = comparisonUtils.findSameObjectAs(dbObjects, toFind); + + assertNull("Should not have found a matching DbObject", found); + } + + private List createMockDbObjects(int size) + { + ArrayList dbObjects = new ArrayList(size); + for (int i = 0; i < size; i++) + { + DbObject dbo = mock(DbObject.class); + when(dbo.toString()).thenReturn("Mock DbObject " + i); + dbObjects.add(dbo); + } + return dbObjects; + } +} diff --git a/source/java/org/alfresco/util/schemacomp/Differences.java b/source/java/org/alfresco/util/schemacomp/Differences.java index f4289c2023..6bb8971638 100644 --- a/source/java/org/alfresco/util/schemacomp/Differences.java +++ b/source/java/org/alfresco/util/schemacomp/Differences.java @@ -23,6 +23,7 @@ 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; @@ -61,10 +62,11 @@ public class Differences implements Iterable * @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) + public void add(Where where, Object left, Object right, Strength strength) { - Result result = new Result(where, left, right, path.getCurrentPath()); + Result result = new Result(where, left, right, path.getCurrentPath(), strength); items.add(result); } diff --git a/source/java/org/alfresco/util/schemacomp/Result.java b/source/java/org/alfresco/util/schemacomp/Result.java index 5b694ba517..708efedc7a 100644 --- a/source/java/org/alfresco/util/schemacomp/Result.java +++ b/source/java/org/alfresco/util/schemacomp/Result.java @@ -29,18 +29,25 @@ public final 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 }; private final Where where; 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) + { + 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); } @@ -80,11 +87,22 @@ public final class Result return this.path; } + + + /** + * @return the strength + */ + public Strength getStrength() + { + return this.strength; + } + + @Override public String toString() { return "Result [where=" + this.where + ", left=" + this.left + ", right=" + this.right - + ", path=" + this.path + "]"; + + ", path=" + this.path + ", strength=" + this.strength + "]"; } } diff --git a/source/java/org/alfresco/util/schemacomp/SchemaCompTestSuite.java b/source/java/org/alfresco/util/schemacomp/SchemaCompTestSuite.java new file mode 100644 index 0000000000..f2f5bf7a8b --- /dev/null +++ b/source/java/org/alfresco/util/schemacomp/SchemaCompTestSuite.java @@ -0,0 +1,37 @@ +/* + * 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 . + */ +package org.alfresco.util.schemacomp; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +/** + * Test suite for tests in the schemacomp package. + * + * @author Matt Ward + */ +@RunWith(Suite.class) +@Suite.SuiteClasses( +{ + DefaultComparisonUtilsTest.class, + SchemaComparatorTest.class +}) +public class SchemaCompTestSuite +{ +} diff --git a/source/java/org/alfresco/util/schemacomp/SchemaComparator.java b/source/java/org/alfresco/util/schemacomp/SchemaComparator.java index 130fa058a4..caa01d46d0 100644 --- a/source/java/org/alfresco/util/schemacomp/SchemaComparator.java +++ b/source/java/org/alfresco/util/schemacomp/SchemaComparator.java @@ -18,6 +18,7 @@ */ package org.alfresco.util.schemacomp; +import org.alfresco.util.schemacomp.Result.Strength; import org.alfresco.util.schemacomp.model.Schema; /** @@ -48,7 +49,7 @@ public class SchemaComparator public void compare() { // Check the left schema against the right schema and record any differences. - leftSchema.diff(rightSchema, differences); + leftSchema.diff(rightSchema, differences, Strength.ERROR); } diff --git a/source/java/org/alfresco/util/schemacomp/SchemaComparatorTest.java b/source/java/org/alfresco/util/schemacomp/SchemaComparatorTest.java index a4712a0835..80b6b43a7c 100644 --- a/source/java/org/alfresco/util/schemacomp/SchemaComparatorTest.java +++ b/source/java/org/alfresco/util/schemacomp/SchemaComparatorTest.java @@ -19,15 +19,19 @@ package org.alfresco.util.schemacomp; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.List; +import org.alfresco.util.schemacomp.Result.Strength; import org.alfresco.util.schemacomp.Result.Where; 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.Index; import org.alfresco.util.schemacomp.model.PrimaryKey; @@ -55,11 +59,6 @@ public class SchemaComparatorTest right = new Schema("right_schema"); } - @Test - public void check() - { - - } @Test public void canPerformDiff() @@ -87,6 +86,8 @@ public class SchemaComparatorTest dumpDiffs(comparator.getDifferences(), true); Iterator it = comparator.getDifferences().iterator(); + + assertHasDifference("left_schema", "left_schema", "right_schema", it.next()); // schema names assertNoDifference("left_schema.tbl_no_diff", "tbl_no_diff", it.next()); assertNoDifference("left_schema.tbl_no_diff.id", "id", it.next()); assertNoDifference("left_schema.tbl_no_diff.id", "NUMBER(10)", it.next()); @@ -126,20 +127,72 @@ public class SchemaComparatorTest assertOnlyInOne("left_schema.tbl_has_diff_pk.pk_is_diff", Where.ONLY_IN_RIGHT, "nodeRef", it.next()); // first (& only) column of list // Items that are ONLY_IN_RIGHT always come at the end + assertEquals("Should be table with correct name", "tbl_has_diff_pk", ((DbObject) it.next().getRight()).getName()); assertOnlyInOne("left_schema", Where.ONLY_IN_RIGHT, table("table_in_right"), it.next()); } + @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); + comparator.compare(); + + dumpDiffs(comparator.getDifferences(), true); + + Iterator 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) + 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. @@ -212,9 +265,7 @@ public class SchemaComparatorTest private PrimaryKey pk(String name, String... columnNames) { assertTrue("No columns specified", columnNames.length > 0); - PrimaryKey pk = new PrimaryKey(); - pk.setName(name); - pk.setColumnNames(Arrays.asList(columnNames)); + PrimaryKey pk = new PrimaryKey(name, Arrays.asList(columnNames)); return pk; } diff --git a/source/java/org/alfresco/util/schemacomp/SchemaUtils.java b/source/java/org/alfresco/util/schemacomp/SchemaUtils.java deleted file mode 100644 index 146e523d7c..0000000000 --- a/source/java/org/alfresco/util/schemacomp/SchemaUtils.java +++ /dev/null @@ -1,132 +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 . - */ - -package org.alfresco.util.schemacomp; - -import java.util.Collection; - -import org.alfresco.util.schemacomp.Result.Where; -import org.alfresco.util.schemacomp.model.DbObject; -import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.collections.Predicate; - -/** - * TODO: comment me! - * - * @author Matt Ward - */ -public abstract class SchemaUtils -{ - /** - * @param objToFind - * @return - */ - public static DbObject findSameObjectAs(Collection objects, - final DbObject objToFind) - { - return (DbObject) CollectionUtils.find(objects, new Predicate() - { - @Override - public boolean evaluate(Object o) - { - DbObject object = (DbObject) o; - return object.sameAs(objToFind); - } - }); - } - - public static void compareSimpleCollections(Collection leftCollection, - Collection rightCollection, Differences differences) - { - for (Object leftObj : leftCollection) - { - if (rightCollection.contains(leftObj)) - { - // The same valued object in the right hand collection as in the left. - differences.add(Where.IN_BOTH_NO_DIFFERENCE, leftObj, leftObj); - } - else - { - // No equivalent object in the right hand collection. - differences.add(Where.ONLY_IN_LEFT, leftObj, null); - } - } - - // Identify objects in the right collection but not the left - for (Object rightObj : rightCollection) - { - if (!leftCollection.contains(rightObj)) - { - // No equivalent object in the left hand collection. - differences.add(Where.ONLY_IN_RIGHT, null, rightObj); - } - } - } - - public static void compareCollections(Collection leftCollection, - Collection rightCollection, Differences differences) - { - for (DbObject leftObj : leftCollection) - { - DbObject rightObj = SchemaUtils.findSameObjectAs(rightCollection, leftObj); - - if (rightObj != null) - { - // There is an equivalent object in the right hand collection as - // in the left. - leftObj.diff(rightObj, differences); - } - else - { - // No equivalent object in the right hand collection. - differences.add(Where.ONLY_IN_LEFT, leftObj, null); - } - } - - // Identify objects in the right collection but not the left - for (DbObject rightObj : rightCollection) - { - if (!leftCollection.contains(rightObj)) - { - // No equivalent object in the left hand collection. - differences.add(Where.ONLY_IN_RIGHT, null, rightObj); - } - } - } - - public static void compareSimple(Object left, Object right, Differences differences) - { - if (left == null && right == null) - { - differences.add(Where.IN_BOTH_NO_DIFFERENCE, null, null); - } - else if (left != null && left.equals(right)) - { - differences.add(Where.IN_BOTH_NO_DIFFERENCE, left, right); - } - else if (left == null && right != null) - { - differences.add(Where.ONLY_IN_RIGHT, null, right); - } - else if (left != null && right == null) - { - differences.add(Where.ONLY_IN_LEFT, left, null); - } - } -} diff --git a/source/java/org/alfresco/util/schemacomp/model/AbstractDbObject.java b/source/java/org/alfresco/util/schemacomp/model/AbstractDbObject.java index 178e8eb020..0456cec4b4 100644 --- a/source/java/org/alfresco/util/schemacomp/model/AbstractDbObject.java +++ b/source/java/org/alfresco/util/schemacomp/model/AbstractDbObject.java @@ -18,8 +18,10 @@ */ package org.alfresco.util.schemacomp.model; +import org.alfresco.util.schemacomp.ComparisonUtils; import org.alfresco.util.schemacomp.Differences; -import org.alfresco.util.schemacomp.SchemaUtils; +import org.alfresco.util.schemacomp.Result.Strength; +import org.alfresco.util.schemacomp.DefaultComparisonUtils; import org.springframework.util.StringUtils; /** @@ -30,7 +32,10 @@ import org.springframework.util.StringUtils; public abstract class AbstractDbObject implements DbObject { private String name; - + /** How differences in the name field should be reported */ + private Strength nameStrength = Strength.ERROR; + protected ComparisonUtils comparisonUtils = new DefaultComparisonUtils(); + /** * Default constructor */ @@ -64,6 +69,22 @@ public abstract class AbstractDbObject implements DbObject this.name = name; } + /** + * @return the nameStrength + */ + public Strength getNameStrength() + { + return this.nameStrength; + } + + /** + * @param nameStrength the nameStrength to set + */ + public void setNameStrength(Strength nameStrength) + { + this.nameStrength = nameStrength; + } + @Override public boolean sameAs(DbObject other) { @@ -133,7 +154,7 @@ public abstract class AbstractDbObject implements DbObject * its diff correctly. */ @Override - public void diff(DbObject right, Differences differences) + public void diff(DbObject right, Differences differences, Strength strength) { if (name != null && StringUtils.hasText(name)) { @@ -143,19 +164,30 @@ public abstract class AbstractDbObject implements DbObject { differences.pushPath("<" + getClass().getSimpleName() + ">"); } - SchemaUtils.compareSimple(name, right.getName(), differences); - doDiff(right, differences); + comparisonUtils.compareSimple(name, right.getName(), differences, getNameStrength()); + doDiff(right, differences, strength); differences.popPath(); } - /** * Override this method to provide subclass specific diffing logic. * * @param right * @param differences + * @param strength */ - protected void doDiff(DbObject right, Differences differences) + protected void doDiff(DbObject right, Differences differences, Strength strength) { } + + /** + * If a ComparisonUtils other than the default is required, then this setter can be used. + * Useful for testing, where a mock can be injected. + * + * @param comparisonUtils the comparisonUtils to set + */ + public void setComparisonUtils(ComparisonUtils comparisonUtils) + { + this.comparisonUtils = comparisonUtils; + } } diff --git a/source/java/org/alfresco/util/schemacomp/model/AbstractDbObjectTest.java b/source/java/org/alfresco/util/schemacomp/model/AbstractDbObjectTest.java new file mode 100644 index 0000000000..c86a22a209 --- /dev/null +++ b/source/java/org/alfresco/util/schemacomp/model/AbstractDbObjectTest.java @@ -0,0 +1,114 @@ +/* + * 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 . + */ +package org.alfresco.util.schemacomp.model; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.inOrder; + +import org.alfresco.util.schemacomp.Differences; +import org.alfresco.util.schemacomp.Result.Strength; +import org.alfresco.util.schemacomp.Result.Where; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InOrder; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +/** + * Tests for the AbstractDbObject base class. + * + * @author Matt Ward + */ +@RunWith(MockitoJUnitRunner.class) +public class AbstractDbObjectTest +{ + private ConcreteDbObject dbObject; + private @Mock Differences differences; + + /** + * @throws java.lang.Exception + */ + @Before + public void setUp() throws Exception + { + dbObject = new ConcreteDbObject("the_object"); + } + + @Test + public void defaultNameStrength() + { + assertEquals(Strength.ERROR, dbObject.getNameStrength()); + } + + @Test + public void sameAs() + { + dbObject.setName(null); + assertFalse("Not the same.", dbObject.sameAs(null)); + assertFalse("Not the same.", dbObject.sameAs(new ConcreteDbObject("other_obj_name"))); + assertTrue("The very same", dbObject.sameAs(dbObject)); + + dbObject.setName("the_name"); + assertFalse("Not the same.", dbObject.sameAs(null)); + assertFalse("Not the same.", dbObject.sameAs(new ConcreteDbObject("different_name"))); + assertTrue("Logically the same object.", dbObject.sameAs(new ConcreteDbObject("the_name"))); + assertTrue("The very same object with non-null name", dbObject.sameAs(dbObject)); + } + + + @Test + public void diff() + { + ConcreteDbObject otherObject = new ConcreteDbObject("the_other_object"); + dbObject.setNameStrength(Strength.WARN); + + dbObject.diff(otherObject, differences, Strength.ERROR); + + 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 + inOrder.verify(differences).add(Where.IN_BOTH_BUT_DIFFERENCE, "the_object", "the_other_object", Strength.WARN); + // Then the doDiff() method should be processed + inOrder.verify(differences).add(Where.IN_BOTH_BUT_DIFFERENCE, "left", "right", Strength.ERROR); + // Later, the path should be popped again + inOrder.verify(differences).popPath(); + } + + + /** + * Concrete DbObject for testing the AbstractDbObject base class. + */ + private static class ConcreteDbObject extends AbstractDbObject + { + public ConcreteDbObject(String name) + { + super(name); + } + + @Override + protected void doDiff(DbObject right, Differences differences, Strength strength) + { + differences.add(Where.IN_BOTH_BUT_DIFFERENCE, "left", "right", strength); + } + } +} diff --git a/source/java/org/alfresco/util/schemacomp/model/Column.java b/source/java/org/alfresco/util/schemacomp/model/Column.java index bd3891125d..67ad47a393 100644 --- a/source/java/org/alfresco/util/schemacomp/model/Column.java +++ b/source/java/org/alfresco/util/schemacomp/model/Column.java @@ -19,7 +19,7 @@ package org.alfresco.util.schemacomp.model; import org.alfresco.util.schemacomp.Differences; -import org.alfresco.util.schemacomp.SchemaUtils; +import org.alfresco.util.schemacomp.Result.Strength; /** * Represents a column in a database table. @@ -105,10 +105,10 @@ public class Column extends AbstractDbObject } @Override - protected void doDiff(DbObject right, Differences differences) + protected void doDiff(DbObject right, Differences differences, Strength strength) { Column rightColumn = (Column) right; - SchemaUtils.compareSimple(type, rightColumn.type, differences); - SchemaUtils.compareSimple(nullable, rightColumn.nullable, differences); + comparisonUtils.compareSimple(type, rightColumn.type, differences); + comparisonUtils.compareSimple(nullable, rightColumn.nullable, differences); } } diff --git a/source/java/org/alfresco/util/schemacomp/model/ColumnTest.java b/source/java/org/alfresco/util/schemacomp/model/ColumnTest.java new file mode 100644 index 0000000000..edb52c1e29 --- /dev/null +++ b/source/java/org/alfresco/util/schemacomp/model/ColumnTest.java @@ -0,0 +1,60 @@ +/* + * 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 . + */ +package org.alfresco.util.schemacomp.model; + + +import org.junit.Before; + +/** + * Tests for the Column class. + * @author Matt Ward + */ +public class ColumnTest extends DbObjectTestBase +{ + private Column thisColumn; + private Column thatColumn; + + + @Before + public void setUp() throws Exception + { + thisColumn = new Column("this_column", "VARCHAR2(100)", false); + thatColumn = new Column("this_column", "NUMBER(10)", true); + } + + @Override + protected Column getThisObject() + { + return thisColumn; + } + + @Override + protected Column getThatObject() + { + return thatColumn; + } + + @Override + protected void doDiffTests() + { + inOrder.verify(comparisonUtils).compareSimple(thisColumn.getType(), thatColumn.getType(), differences); + inOrder.verify(comparisonUtils).compareSimple(thisColumn.isNullable(), thatColumn.isNullable(), differences); + } + +} diff --git a/source/java/org/alfresco/util/schemacomp/model/DbObject.java b/source/java/org/alfresco/util/schemacomp/model/DbObject.java index af002fe3ae..66707bbd9f 100644 --- a/source/java/org/alfresco/util/schemacomp/model/DbObject.java +++ b/source/java/org/alfresco/util/schemacomp/model/DbObject.java @@ -19,6 +19,7 @@ package org.alfresco.util.schemacomp.model; import org.alfresco.util.schemacomp.Differences; +import org.alfresco.util.schemacomp.Result.Strength; /** * All database objects to be modelled for schema comparisons must implement this interface, examples @@ -31,6 +32,11 @@ public interface DbObject /** * Are the two DbObjects logically the same? For example two Index objects may have * different names, but are the same index as they both index the same columns for the same table. + *

+ * If two objects a and b have the same logical identity, it does not mean that a.equals(b) == true. + * The two objects may well have differences and will be flagged as such by the schema comparison tool. When + * a.sameAs(b) == true it makes it easier to show the differences as related, i.e. a and b are + * different rather than, a is only in the 'left' tree and b is only in the 'right' tree. * * @param other * @return @@ -52,5 +58,5 @@ public interface DbObject * @param right The object to compare against. * @param differences A collector of differences. */ - void diff(DbObject right, Differences differences); + void diff(DbObject right, Differences differences, Strength strength); } diff --git a/source/java/org/alfresco/util/schemacomp/model/DbObjectTestBase.java b/source/java/org/alfresco/util/schemacomp/model/DbObjectTestBase.java new file mode 100644 index 0000000000..85351a36e0 --- /dev/null +++ b/source/java/org/alfresco/util/schemacomp/model/DbObjectTestBase.java @@ -0,0 +1,102 @@ +/* + * 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 . + */ +package org.alfresco.util.schemacomp.model; + +import static org.mockito.Mockito.inOrder; + +import java.util.ArrayList; +import java.util.List; + +import org.alfresco.util.schemacomp.ComparisonUtils; +import org.alfresco.util.schemacomp.Differences; +import org.alfresco.util.schemacomp.Result.Strength; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InOrder; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +/** + * Abstract base class for tests for AbstractDbObject subclasses. + * + * @author Matt Ward + */ +@RunWith(MockitoJUnitRunner.class) +public abstract class DbObjectTestBase +{ + protected @Mock Differences differences; + protected @Mock ComparisonUtils comparisonUtils; + protected InOrder inOrder; + protected abstract T getThisObject(); + protected abstract T getThatObject(); + + @Before + public void setUpMockito() + { + // Check that the correct calls happened in the correct order. + List mocks = getMocksUsedInDiff(); + inOrder = inOrder(mocks.toArray()); + } + + + /** + * Override to add additional mocks to the InOrder call verification. + * + * @return List + */ + protected List getMocksUsedInDiff() + { + List objects = new ArrayList(); + objects.add(differences); + objects.add(comparisonUtils); + return objects; + } + + + @Test + public void canDiffObjects() + { + AbstractDbObject thisObject = getThisObject(); + thisObject.setComparisonUtils(comparisonUtils); + AbstractDbObject thatObject = getThatObject(); + thatObject.setComparisonUtils(comparisonUtils); + + // Invoke the method under test + thisObject.diff(thatObject, differences, 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 + inOrder.verify(comparisonUtils).compareSimple( + thisObject.getName(), + thatObject.getName(), + differences, + thisObject.getNameStrength()); + + // Then the doDiff() method should be processed... + doDiffTests(); + + // Later, the path should be popped again + inOrder.verify(differences).popPath(); + } + + protected abstract void doDiffTests(); +} diff --git a/source/java/org/alfresco/util/schemacomp/model/ForeignKey.java b/source/java/org/alfresco/util/schemacomp/model/ForeignKey.java index 5dddb6dddf..24cb734b14 100644 --- a/source/java/org/alfresco/util/schemacomp/model/ForeignKey.java +++ b/source/java/org/alfresco/util/schemacomp/model/ForeignKey.java @@ -19,7 +19,7 @@ package org.alfresco.util.schemacomp.model; import org.alfresco.util.schemacomp.Differences; -import org.alfresco.util.schemacomp.SchemaUtils; +import org.alfresco.util.schemacomp.Result.Strength; /** @@ -137,11 +137,11 @@ public class ForeignKey extends AbstractDbObject @Override - protected void doDiff(DbObject right, Differences differences) + protected void doDiff(DbObject right, Differences differences, Strength strength) { ForeignKey rightFK = (ForeignKey) right; - SchemaUtils.compareSimple(localColumn, rightFK.localColumn, differences); - SchemaUtils.compareSimple(targetTable, rightFK.targetTable, differences); - SchemaUtils.compareSimple(targetColumn, rightFK.targetColumn, differences); + comparisonUtils.compareSimple(localColumn, rightFK.localColumn, differences); + comparisonUtils.compareSimple(targetTable, rightFK.targetTable, differences); + comparisonUtils.compareSimple(targetColumn, rightFK.targetColumn, differences); } } diff --git a/source/java/org/alfresco/util/schemacomp/model/ForeignKeyTest.java b/source/java/org/alfresco/util/schemacomp/model/ForeignKeyTest.java new file mode 100644 index 0000000000..af49e4c8e9 --- /dev/null +++ b/source/java/org/alfresco/util/schemacomp/model/ForeignKeyTest.java @@ -0,0 +1,63 @@ +/* + * 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 . + */ +package org.alfresco.util.schemacomp.model; + + +import org.junit.Before; + +/** + * Tests for the ForeignKey class. + * + * @author Matt Ward + */ +public class ForeignKeyTest extends DbObjectTestBase +{ + private ForeignKey thisFK, thatFK; + + + @Before + public void setUp() throws Exception + { + thisFK = new ForeignKey("this_fk", "local_col", "target_table", "target_col"); + thatFK = new ForeignKey("that_fk", "local_col", "target_table", "target_col"); + } + + + @Override + protected ForeignKey getThisObject() + { + return thisFK; + } + + + @Override + protected ForeignKey getThatObject() + { + return thatFK; + } + + + @Override + protected void doDiffTests() + { + inOrder.verify(comparisonUtils).compareSimple(thisFK.getLocalColumn(), thatFK.getLocalColumn(), differences); + inOrder.verify(comparisonUtils).compareSimple(thisFK.getTargetTable(), thatFK.getTargetTable(), differences); + inOrder.verify(comparisonUtils).compareSimple(thisFK.getTargetColumn(), thatFK.getTargetColumn(), differences); + } +} diff --git a/source/java/org/alfresco/util/schemacomp/model/Index.java b/source/java/org/alfresco/util/schemacomp/model/Index.java index 5e7a0f774b..b01ba50d7f 100644 --- a/source/java/org/alfresco/util/schemacomp/model/Index.java +++ b/source/java/org/alfresco/util/schemacomp/model/Index.java @@ -21,7 +21,7 @@ package org.alfresco.util.schemacomp.model; import java.util.List; import org.alfresco.util.schemacomp.Differences; -import org.alfresco.util.schemacomp.SchemaUtils; +import org.alfresco.util.schemacomp.Result.Strength; /** * Represents an index on a table. @@ -40,6 +40,7 @@ public class Index extends AbstractDbObject { super(name); this.columnNames = columnNames; + setNameStrength(Strength.WARN); } /** @@ -105,10 +106,11 @@ public class Index extends AbstractDbObject return false; } + @Override - protected void doDiff(DbObject right, Differences differences) + protected void doDiff(DbObject right, Differences differences, Strength strength) { Index rightIndex = (Index) right; - SchemaUtils.compareSimpleCollections(columnNames, rightIndex.columnNames, differences); + comparisonUtils.compareSimpleCollections(columnNames, rightIndex.columnNames, differences, strength); } } diff --git a/source/java/org/alfresco/util/schemacomp/model/IndexTest.java b/source/java/org/alfresco/util/schemacomp/model/IndexTest.java new file mode 100644 index 0000000000..fbe8f25102 --- /dev/null +++ b/source/java/org/alfresco/util/schemacomp/model/IndexTest.java @@ -0,0 +1,93 @@ +/* + * 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 . + */ +package org.alfresco.util.schemacomp.model; + +import java.util.Arrays; + +import org.alfresco.util.schemacomp.Result.Strength; +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.*; + + +/** + * Tests for the Index class. + * @author Matt Ward + */ +public class IndexTest extends DbObjectTestBase +{ + private Index thisIndex; + private Index thatIndex; + + @Before + public void setUp() + { + thisIndex = new Index("this_index", Arrays.asList("id", "name", "age")); + thatIndex = new Index("that_index", Arrays.asList("a", "b")); + } + + @Override + protected Index getThisObject() + { + return thisIndex; + } + + @Override + protected Index getThatObject() + { + return thatIndex; + } + + @Override + protected void doDiffTests() + { + inOrder.verify(comparisonUtils).compareSimpleCollections( + thisIndex.getColumnNames(), + thatIndex.getColumnNames(), + differences, + Strength.ERROR); + } + + + @Test + public void differentNamesResultInWarningsNotErrors() + { + assertEquals("Name differences should be reported as warnings.", Strength.WARN, thisIndex.getNameStrength()); + } + + + @Test + public void sameAs() + { + assertTrue("Indexes should be logically the same.", + thisIndex.sameAs(new Index("this_index", Arrays.asList("id", "name", "age")))); + + 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")))); + + 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")))); + + assertFalse("Indexes should be identified different (different name and column order)", + thisIndex.sameAs(new Index("different_name", Arrays.asList("name", "id", "age")))); + + assertFalse("Indexes should be identified different (different name & different columns)", + thisIndex.sameAs(new Index("different_name", Arrays.asList("node_ref", "url")))); + } +} diff --git a/source/java/org/alfresco/util/schemacomp/model/ModelTestSuite.java b/source/java/org/alfresco/util/schemacomp/model/ModelTestSuite.java new file mode 100644 index 0000000000..6c7d8714c7 --- /dev/null +++ b/source/java/org/alfresco/util/schemacomp/model/ModelTestSuite.java @@ -0,0 +1,44 @@ +/* + * 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 . + */ +package org.alfresco.util.schemacomp.model; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +/** + * Test suite for all the model tests. + * + * @author Matt Ward + */ +@RunWith(Suite.class) +@Suite.SuiteClasses( +{ + AbstractDbObjectTest.class, + ColumnTest.class, + ForeignKeyTest.class, + IndexTest.class, + PrimaryKeyTest.class, + SchemaTest.class, + SequenceTest.class, + TableTest.class +}) +public class ModelTestSuite +{ + // Suite defined by annotation above. +} diff --git a/source/java/org/alfresco/util/schemacomp/model/PrimaryKey.java b/source/java/org/alfresco/util/schemacomp/model/PrimaryKey.java index c740d5cf98..0c15ab4749 100644 --- a/source/java/org/alfresco/util/schemacomp/model/PrimaryKey.java +++ b/source/java/org/alfresco/util/schemacomp/model/PrimaryKey.java @@ -21,7 +21,7 @@ package org.alfresco.util.schemacomp.model; import java.util.List; import org.alfresco.util.schemacomp.Differences; -import org.alfresco.util.schemacomp.SchemaUtils; +import org.alfresco.util.schemacomp.Result.Strength; /** * Primary key on a table. @@ -33,6 +33,17 @@ public class PrimaryKey extends AbstractDbObject private List columnNames; + /** + * Constructor + * @param name + * @param columnNames + */ + public PrimaryKey(String name, List columnNames) + { + super(name); + this.columnNames = columnNames; + } + /** * @return the columnNames */ @@ -74,9 +85,9 @@ public class PrimaryKey extends AbstractDbObject } @Override - protected void doDiff(DbObject right, Differences differences) + protected void doDiff(DbObject right, Differences differences, Strength strength) { PrimaryKey rightPK = (PrimaryKey) right; - SchemaUtils.compareSimpleCollections(columnNames, rightPK.columnNames, differences); + comparisonUtils.compareSimpleCollections(columnNames, rightPK.columnNames, differences, strength); } } diff --git a/source/java/org/alfresco/util/schemacomp/model/PrimaryKeyTest.java b/source/java/org/alfresco/util/schemacomp/model/PrimaryKeyTest.java new file mode 100644 index 0000000000..7a4ebaefa4 --- /dev/null +++ b/source/java/org/alfresco/util/schemacomp/model/PrimaryKeyTest.java @@ -0,0 +1,66 @@ +/* + * 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 . + */ +package org.alfresco.util.schemacomp.model; + +import java.util.Arrays; + +import org.alfresco.util.schemacomp.Result.Strength; +import org.junit.Before; + + +/** + * Tests for the PrimaryKey class. + * + * @author Matt Ward + */ +public class PrimaryKeyTest extends DbObjectTestBase +{ + private PrimaryKey thisPK; + private PrimaryKey thatPK; + + @Before + public void setUp() + { + thisPK = new PrimaryKey("this_pk", Arrays.asList("id", "name", "age")); + thatPK = new PrimaryKey("that_pk", Arrays.asList("a", "b")); + } + + @Override + protected PrimaryKey getThisObject() + { + return thisPK; + } + + @Override + protected PrimaryKey getThatObject() + { + return thatPK; + } + + @Override + protected void doDiffTests() + { + inOrder.verify(comparisonUtils).compareSimpleCollections( + thisPK.getColumnNames(), + thatPK.getColumnNames(), + differences, + Strength.ERROR); + } + +} diff --git a/source/java/org/alfresco/util/schemacomp/model/Schema.java b/source/java/org/alfresco/util/schemacomp/model/Schema.java index 89f65cbd5f..da5ee3a261 100644 --- a/source/java/org/alfresco/util/schemacomp/model/Schema.java +++ b/source/java/org/alfresco/util/schemacomp/model/Schema.java @@ -23,7 +23,7 @@ import java.util.Iterator; import java.util.List; import org.alfresco.util.schemacomp.Differences; -import org.alfresco.util.schemacomp.SchemaUtils; +import org.alfresco.util.schemacomp.Result.Strength; /** * Instances of this class represent a database schema. @@ -32,7 +32,7 @@ import org.alfresco.util.schemacomp.SchemaUtils; */ public class Schema extends AbstractDbObject implements Iterable { - private final List objects = new ArrayList(); + protected final List objects = new ArrayList(); /** * Construct a schema with the given name. @@ -90,9 +90,9 @@ public class Schema extends AbstractDbObject implements Iterable @Override - protected void doDiff(DbObject right, Differences differences) + protected void doDiff(DbObject right, Differences differences, Strength strength) { Schema rightSchema = (Schema) right; - SchemaUtils.compareCollections(objects, rightSchema.objects, differences); + comparisonUtils.compareCollections(objects, rightSchema.objects, differences); } } diff --git a/source/java/org/alfresco/util/schemacomp/model/SchemaTest.java b/source/java/org/alfresco/util/schemacomp/model/SchemaTest.java new file mode 100644 index 0000000000..899d4529f1 --- /dev/null +++ b/source/java/org/alfresco/util/schemacomp/model/SchemaTest.java @@ -0,0 +1,62 @@ +/* + * 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 . + */ +package org.alfresco.util.schemacomp.model; + +import org.junit.Before; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; + +/** + * Tests for the Schema class. + * + * @author Matt Ward + */ +@RunWith(MockitoJUnitRunner.class) +public class SchemaTest extends DbObjectTestBase +{ + private Schema left; + private Schema right; + + @Before + public void setUp() + { + left = new Schema("left_schema"); + right = new Schema("right_schema"); + } + + @Override + protected Schema getThisObject() + { + return left; + } + + @Override + protected Schema getThatObject() + { + return right; + } + + @Override + protected void doDiffTests() + { + // In addition to the base class functionality, Schema.diff() compares + // the DbObjects held in the other schema with its own DbObjects. + inOrder.verify(comparisonUtils).compareCollections(left.objects, right.objects, differences); + } +} diff --git a/source/java/org/alfresco/util/schemacomp/model/SequenceTest.java b/source/java/org/alfresco/util/schemacomp/model/SequenceTest.java new file mode 100644 index 0000000000..a53ef1844b --- /dev/null +++ b/source/java/org/alfresco/util/schemacomp/model/SequenceTest.java @@ -0,0 +1,36 @@ +/* + * 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 . + */ +package org.alfresco.util.schemacomp.model; + +import org.junit.Ignore; +import org.junit.Test; + +/** + * Tests for the Sequence class. + * @author Matt Ward + */ +public class SequenceTest +{ + @Ignore + @Test + public void noTestsRequired() + { + // No functionality over and above AbstractDbObject at present. + } +} diff --git a/source/java/org/alfresco/util/schemacomp/model/Table.java b/source/java/org/alfresco/util/schemacomp/model/Table.java index e79fc36614..8a9d2811a5 100644 --- a/source/java/org/alfresco/util/schemacomp/model/Table.java +++ b/source/java/org/alfresco/util/schemacomp/model/Table.java @@ -23,7 +23,7 @@ import java.util.Collection; import java.util.List; import org.alfresco.util.schemacomp.Differences; -import org.alfresco.util.schemacomp.SchemaUtils; +import org.alfresco.util.schemacomp.Result.Strength; /** * Instances of this class represent a database table. @@ -165,24 +165,22 @@ public class Table extends AbstractDbObject if (other.indexes != null) return false; } else if (!this.indexes.equals(other.indexes)) return false; - // TODO: this is difficult, equals probably should include this, but diffs shouldn't - - // decide what to do about this. -// if (this.primaryKey == null) -// { -// if (other.primaryKey != null) return false; -// } -// else if (!this.primaryKey.equals(other.primaryKey)) return false; + if (this.primaryKey == null) + { + if (other.primaryKey != null) return false; + } + else if (!this.primaryKey.equals(other.primaryKey)) return false; return true; } @Override - protected void doDiff(DbObject other, Differences differences) + protected void doDiff(DbObject other, Differences differences, Strength strength) { Table rightTable = (Table) other; - SchemaUtils.compareCollections(columns, rightTable.columns, differences); - primaryKey.diff(rightTable.primaryKey, differences); - SchemaUtils.compareCollections(foreignKeys, rightTable.foreignKeys, differences); - SchemaUtils.compareCollections(indexes, rightTable.indexes, differences); + comparisonUtils.compareCollections(columns, rightTable.columns, differences); + primaryKey.diff(rightTable.primaryKey, differences, strength); + comparisonUtils.compareCollections(foreignKeys, rightTable.foreignKeys, differences); + comparisonUtils.compareCollections(indexes, rightTable.indexes, differences); } } diff --git a/source/java/org/alfresco/util/schemacomp/model/TableTest.java b/source/java/org/alfresco/util/schemacomp/model/TableTest.java new file mode 100644 index 0000000000..6cb9fe21ed --- /dev/null +++ b/source/java/org/alfresco/util/schemacomp/model/TableTest.java @@ -0,0 +1,102 @@ +/* + * 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 . + */ +package org.alfresco.util.schemacomp.model; + + +import static java.util.Arrays.asList; + +import java.util.Collection; +import java.util.List; + +import org.alfresco.util.schemacomp.Result.Strength; +import org.junit.Before; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +/** + * Tests for the Table class. + * + * @author Matt Ward + */ +@RunWith(MockitoJUnitRunner.class) +public class TableTest extends DbObjectTestBase +{ + private Table table; + private Table otherTable; + private Collection columns; + private @Mock PrimaryKey primaryKey; + private Collection foreignKeys; + private Collection indexes; + + + @Before + 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); + } + + + @Override + protected List getMocksUsedInDiff() + { + List mocks = super.getMocksUsedInDiff(); + mocks.add(primaryKey); + return mocks; + } + + public void doDiffTests() + { + // Check columns + inOrder.verify(comparisonUtils).compareCollections(table.getColumns(), otherTable.getColumns(), differences); + + // Check primary key + inOrder.verify(primaryKey).diff(otherTable.getPrimaryKey(), differences, Strength.ERROR); + + // Check foreign keys + inOrder.verify(comparisonUtils).compareCollections( + table.getForeignKeys(), otherTable.getForeignKeys(), differences); + + // Check indexes + inOrder.verify(comparisonUtils).compareCollections( + table.getIndexes(), otherTable.getIndexes(), differences); + } + + @Override + protected Table getThisObject() + { + return table; + } + + @Override + protected Table getThatObject() + { + return otherTable; + } +}