From 4f2db10b1958c9650c82ff35f369e6a0ea76e7a1 Mon Sep 17 00:00:00 2001 From: tom Date: Tue, 14 May 2013 22:17:08 +0200 Subject: [PATCH 1/2] Introduced DependencyPrescription and Proscription. --- .../framework/DependencyConstraint.java | 149 ++---------------- .../framework/DependencyDirective.java | 63 ++++++++ .../framework/DependencyPrescription.java | 129 +++++++++++++++ .../framework/DependencyProscription.java | 60 +++++++ src/jdepend/framework/JDepend.java | 30 +++- test/jdepend/framework/ComponentTest.java | 8 +- .../framework/DependencyProscriptionTest.java | 52 ++++++ test/jdepend/framework/FileManagerTest.java | 2 +- test/jdepend/framework/MetricTest.java | 8 +- 9 files changed, 346 insertions(+), 155 deletions(-) create mode 100644 src/jdepend/framework/DependencyDirective.java create mode 100644 src/jdepend/framework/DependencyPrescription.java create mode 100644 src/jdepend/framework/DependencyProscription.java create mode 100644 test/jdepend/framework/DependencyProscriptionTest.java diff --git a/src/jdepend/framework/DependencyConstraint.java b/src/jdepend/framework/DependencyConstraint.java index eaaa01f..bf808af 100755 --- a/src/jdepend/framework/DependencyConstraint.java +++ b/src/jdepend/framework/DependencyConstraint.java @@ -5,156 +5,27 @@ import jdepend.framework.JavaPackage; /** - * The DependencyConstraint class is a constraint that tests - * whether two package-dependency graphs are equivalent. + * This class has been replaced by DependencyPrescription. *

- * This class is useful for writing package dependency assertions (e.g. JUnit). - * For example, the following JUnit test will ensure that the 'ejb' and 'web' - * packages only depend upon the 'util' package, and no others: - *

- *

- * - *
- * 
- * public void testDependencyConstraint() {
- * 
- *     JDepend jdepend = new JDepend();
- *     jdepend.addDirectory("/path/to/classes");
- *     Collection analyzedPackages = jdepend.analyze();
- * 
- *     DependencyConstraint constraint = new DependencyConstraint();
- * 
- *     JavaPackage ejb = constraint.addPackage("com.xyz.ejb");
- *     JavaPackage web = constraint.addPackage("com.xyz.web");
- *     JavaPackage util = constraint.addPackage("com.xyz.util");
- * 
- *     ejb.dependsUpon(util);
- *     web.dependsUpon(util);
- * 
- *     assertEquals("Dependency mismatch", true, constraint
- *             .match(analyzedPackages));
- * }
- * 
- * - *
- *

- * - * @author Mike Clark - * @author Clarkware Consulting, Inc. + * @deprecated use DependencyPrescription instead. */ - public class DependencyConstraint { - private HashMap packages; - - public DependencyConstraint() { - packages = new HashMap(); - } - + private DependencyPrescription prescription = new DependencyPrescription(); + public JavaPackage addPackage(String packageName) { - JavaPackage jPackage = (JavaPackage) packages.get(packageName); - if (jPackage == null) { - jPackage = new JavaPackage(packageName); - addPackage(jPackage); - } - return jPackage; + return prescription.addPackage(packageName); } public void addPackage(JavaPackage jPackage) { - if (!packages.containsValue(jPackage)) { - packages.put(jPackage.getName(), jPackage); - } - } - - public Collection getPackages() { - return packages.values(); + prescription.addPackage(jPackage); } - /** - * Indicates whether the specified packages match the - * packages in this constraint. - * - * @return true if the packages match this constraint - */ - public boolean match(Collection expectedPackages) { - - if (packages.size() == expectedPackages.size()) { - - for (Iterator i = expectedPackages.iterator(); i.hasNext();) { - Object next = i.next(); - if (next instanceof JavaPackage) { - JavaPackage nextPackage = (JavaPackage) next; - if (!matchPackage(nextPackage)) { - return false; - } - } else { - break; - } - - return true; - } - } - - return false; - } - - private boolean matchPackage(JavaPackage expectedPackage) { - - JavaPackage actualPackage = (JavaPackage) packages.get(expectedPackage - .getName()); - - if (actualPackage != null) { - if (equalsDependencies(actualPackage, expectedPackage)) { - return true; - } - } - - return false; + public Collection getPackages() { + return prescription.getPackages(); } - private boolean equalsDependencies(JavaPackage a, JavaPackage b) { - return equalsAfferents(a, b) && equalsEfferents(a, b); - } - - private boolean equalsAfferents(JavaPackage a, JavaPackage b) { - - if (a.equals(b)) { - - Collection otherAfferents = b.getAfferents(); - - if (a.getAfferents().size() == otherAfferents.size()) { - for (Iterator i = a.getAfferents().iterator(); i.hasNext();) { - JavaPackage afferent = (JavaPackage)i.next(); - if (!otherAfferents.contains(afferent)) { - return false; - } - } - - return true; - } - } - - return false; - } - - private boolean equalsEfferents(JavaPackage a, JavaPackage b) { - - if (a.equals(b)) { - - Collection otherEfferents = b.getEfferents(); - - if (a.getEfferents().size() == otherEfferents.size()) { - for (Iterator i = a.getEfferents().iterator(); i.hasNext();) { - JavaPackage efferent = (JavaPackage)i.next(); - if (!otherEfferents.contains(efferent)) { - return false; - } - } - - return true; - } - } - - return false; + public boolean match(Collection expectedPackages) { + return prescription.followsDirective(expectedPackages); } } \ No newline at end of file diff --git a/src/jdepend/framework/DependencyDirective.java b/src/jdepend/framework/DependencyDirective.java new file mode 100644 index 0000000..adbfd0b --- /dev/null +++ b/src/jdepend/framework/DependencyDirective.java @@ -0,0 +1,63 @@ +package jdepend.framework; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** + * A DependencyDirective represents a set of dependency + * instructions to which analysed code can be compared. + *

+ * Concrete subclasses implement the comparing functionality. + * + * @author Tom van den Berge + */ +public abstract class DependencyDirective { + + protected Map packages = new HashMap(); + + /** + * Adds the specified package to this directive. The returned JavaPackage + * can be used to couple to other packages. + * + * @param packageName + * the name of the package. + * @return the added package. + */ + public JavaPackage addPackage(String packageName) { + JavaPackage jPackage = (JavaPackage) packages.get(packageName); + if (jPackage == null) { + jPackage = new JavaPackage(packageName); + addPackage(jPackage); + } + return jPackage; + } + + /** + * Adds the specified package to this directive. + * + * @param jPackage the package to add. + */ + public void addPackage(JavaPackage jPackage) { + if (!packages.containsValue(jPackage)) { + packages.put(jPackage.getName(), jPackage); + } + } + + /** + * Returns all configured packages of this directive. + * + * @return the packages. + */ + public Collection getPackages() { + return packages.values(); + } + + /** + * Returns true if the specified packages follow this directive. + * + * @param packages the packages to verify against this directive. + * @return true if the packages follow this directive, otherwise false. + */ + public abstract boolean followsDirective(Collection packages); +} diff --git a/src/jdepend/framework/DependencyPrescription.java b/src/jdepend/framework/DependencyPrescription.java new file mode 100644 index 0000000..375e8a9 --- /dev/null +++ b/src/jdepend/framework/DependencyPrescription.java @@ -0,0 +1,129 @@ +package jdepend.framework; + +import java.util.Collection; +import java.util.Iterator; + +/** + * The DependencyPrescription class is a constraint that tests + * whether two package-dependency graphs are equivalent. + *

+ * This class is useful for writing package dependency assertions (e.g. JUnit). + * For example, the following JUnit test will ensure that the 'ejb' and 'web' + * packages only depend upon the 'util' package, and no others: + *

+ *

+ * + *
+ * 
+ * public void testDependencyConstraint() {
+ * 
+ *     JDepend jdepend = new JDepend();
+ *     jdepend.addDirectory("/path/to/classes");
+ *     Collection analyzedPackages = jdepend.analyze();
+ * 
+ *     DependencyPrescription constraint = new DependencyPrescription();
+ * 
+ *     JavaPackage ejb = constraint.addPackage("com.xyz.ejb");
+ *     JavaPackage web = constraint.addPackage("com.xyz.web");
+ *     JavaPackage util = constraint.addPackage("com.xyz.util");
+ * 
+ *     ejb.dependsUpon(util);
+ *     web.dependsUpon(util);
+ * 
+ *     assertEquals("Dependency mismatch", true, constraint
+ *             .followsDirective(analyzedPackages));
+ * }
+ * 
+ * + *
+ *

+ * + * @author Mike Clark + * @author Clarkware Consulting, Inc. + */ +public class DependencyPrescription extends DependencyDirective { + + /** + * Indicates whether the specified packages match the packages in this + * prescription. + * + * @return true if the packages match this constraint + */ + @Override + public boolean followsDirective(Collection packages) { + if (packages.size() == packages.size()) { + + for (Iterator i = packages.iterator(); i.hasNext();) { + Object next = i.next(); + JavaPackage nextPackage = (JavaPackage) next; + if (!matchPackage(nextPackage)) { + return false; + } + + return true; + } + } + + return false; + } + + private boolean matchPackage(JavaPackage expectedPackage) { + + JavaPackage actualPackage = (JavaPackage) packages.get(expectedPackage + .getName()); + + if (actualPackage != null) { + if (equalsDependencies(actualPackage, expectedPackage)) { + return true; + } + } + + return false; + } + + private boolean equalsDependencies(JavaPackage a, JavaPackage b) { + return equalsAfferents(a, b) && equalsEfferents(a, b); + } + + private boolean equalsAfferents(JavaPackage a, JavaPackage b) { + + if (a.equals(b)) { + + Collection otherAfferents = b.getAfferents(); + + if (a.getAfferents().size() == otherAfferents.size()) { + for (Iterator i = a.getAfferents().iterator(); i.hasNext();) { + JavaPackage afferent = (JavaPackage) i.next(); + if (!otherAfferents.contains(afferent)) { + return false; + } + } + + return true; + } + } + + return false; + } + + private boolean equalsEfferents(JavaPackage a, JavaPackage b) { + + if (a.equals(b)) { + + Collection otherEfferents = b.getEfferents(); + + if (a.getEfferents().size() == otherEfferents.size()) { + for (Iterator i = a.getEfferents().iterator(); i.hasNext();) { + JavaPackage efferent = (JavaPackage) i.next(); + if (!otherEfferents.contains(efferent)) { + return false; + } + } + + return true; + } + } + + return false; + } +} diff --git a/src/jdepend/framework/DependencyProscription.java b/src/jdepend/framework/DependencyProscription.java new file mode 100644 index 0000000..7703581 --- /dev/null +++ b/src/jdepend/framework/DependencyProscription.java @@ -0,0 +1,60 @@ +package jdepend.framework; + +import java.util.Collection; +import java.util.HashSet; + +/** + * The DependencyProscription defines a set of disallowed package + * dependencies. It can be used to verify that a set of packages do not + * have any unwanted dependencies. + * + * @author Tom van den Berge. + */ +public class DependencyProscription extends DependencyDirective { + + @Override + public boolean followsDirective(Collection packages) { + for (JavaPackage pckg : packages) { + if (hasDisallowedCouplings(pckg)) { + return false; + } + } + return true; + } + + private boolean hasDisallowedCouplings(JavaPackage verifiedPackage) { + JavaPackage restrictedPackage = packages.get(verifiedPackage.getName()); + + if (restrictedPackage == null) { + return false; + } + + if (hasDisallowedAfferents(restrictedPackage, verifiedPackage)) { + return true; + } + + if (hasDisallowedEfferents(restrictedPackage, verifiedPackage)) { + return true; + } + + return false; + } + + private boolean hasDisallowedAfferents(JavaPackage restrictedPackage, JavaPackage verifiedPackage) { + final Collection disallowedAfferents = restrictedPackage + .getAfferents(); + final Collection actualAfferents = new HashSet( + verifiedPackage.getAfferents()); + actualAfferents.retainAll(disallowedAfferents); + return !actualAfferents.isEmpty(); + } + + private boolean hasDisallowedEfferents(JavaPackage restrictedPackage, JavaPackage verifiedPackage) { + final Collection disallowedEfferents = restrictedPackage + .getEfferents(); + final Collection actualEfferents = new HashSet( + verifiedPackage.getEfferents()); + actualEfferents.retainAll(disallowedEfferents); + return !actualEfferents.isEmpty(); + } +} diff --git a/src/jdepend/framework/JDepend.java b/src/jdepend/framework/JDepend.java index b400174..9efc770 100755 --- a/src/jdepend/framework/JDepend.java +++ b/src/jdepend/framework/JDepend.java @@ -1,7 +1,11 @@ package jdepend.framework; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.StringTokenizer; /** * The JDepend class analyzes directories of Java class files @@ -234,16 +238,28 @@ public boolean containsCycles() { } /** - * Indicates whether the analyzed packages match the specified - * dependency constraint. - * - * @return true if the packages match the dependency - * constraint - */ + * Indicates whether the analyzed packages match the specified dependency + * constraint. + * + * @return true if the packages match the dependency constraint + * @deprecated use {@link #followsDirective(DependencyDirective)} instead. + */ public boolean dependencyMatch(DependencyConstraint constraint) { return constraint.match(getPackages()); } + /** + * Indicates whether the analyzed packages follow the specified dependency + * directive. + * + * @param directive + * the directive that is verified. + * @return true if the packages follow the directive. + */ + public boolean followsDirective(DependencyDirective directive) { + return directive.followsDirective(getPackages()); + } + /** * Registers the specified parser listener. * diff --git a/test/jdepend/framework/ComponentTest.java b/test/jdepend/framework/ComponentTest.java index f509d4d..8aeaa26 100644 --- a/test/jdepend/framework/ComponentTest.java +++ b/test/jdepend/framework/ComponentTest.java @@ -53,13 +53,13 @@ public void testJDependComponents() throws IOException { private void assertJDependPackage() { JavaPackage p = jdepend.getPackage("jdepend"); assertEquals("jdepend", p.getName()); - assertEquals(36, p.getConcreteClassCount()); - assertEquals(7, p.getAbstractClassCount()); + assertEquals(40, p.getConcreteClassCount()); + assertEquals(8, p.getAbstractClassCount()); assertEquals(0, p.afferentCoupling()); assertEquals(5, p.efferentCoupling()); - assertEquals(format(0.16f), format(p.abstractness())); + assertEquals(format(0.17f), format(p.abstractness())); assertEquals("1", format(p.instability())); - assertEquals(format(0.16f), format(p.distance())); + assertEquals(format(0.17f), format(p.distance())); assertEquals(1, p.getVolatility()); Collection efferents = p.getEfferents(); diff --git a/test/jdepend/framework/DependencyProscriptionTest.java b/test/jdepend/framework/DependencyProscriptionTest.java new file mode 100644 index 0000000..6560bd2 --- /dev/null +++ b/test/jdepend/framework/DependencyProscriptionTest.java @@ -0,0 +1,52 @@ +package jdepend.framework; + +public class DependencyProscriptionTest extends JDependTestCase { + + private JDepend jdepend; + + public DependencyProscriptionTest(String name) { + super(name); + } + + protected void setUp() { + super.setUp(); + } + + public void testPass() { + DependencyDirective proscription = new DependencyProscription(); + + JavaPackage expectedA = proscription.addPackage("A"); + JavaPackage expectedB = proscription.addPackage("B"); + + expectedA.dependsUpon(expectedB); + + JavaPackage actualA = new JavaPackage("A"); + JavaPackage actualB = new JavaPackage("B"); + + actualB.dependsUpon(actualA); + + jdepend.addPackage(actualA); + jdepend.addPackage(actualB); + + assertEquals(true, jdepend.followsDirective(proscription)); + } + + public void testFail() { + DependencyDirective proscription = new DependencyProscription(); + + JavaPackage forbiddenA = proscription.addPackage("A"); + JavaPackage forbiddenB = proscription.addPackage("B"); + + forbiddenA.dependsUpon(forbiddenB); + + JavaPackage actualA = new JavaPackage("A"); + JavaPackage actualB = new JavaPackage("B"); + + actualA.dependsUpon(actualB); + + jdepend.addPackage(actualA); + jdepend.addPackage(actualB); + + assertEquals(false, jdepend.followsDirective(proscription)); + } +} diff --git a/test/jdepend/framework/FileManagerTest.java b/test/jdepend/framework/FileManagerTest.java index dddf00d..b69f208 100755 --- a/test/jdepend/framework/FileManagerTest.java +++ b/test/jdepend/framework/FileManagerTest.java @@ -32,7 +32,7 @@ public void testEmptyFileManager() { public void testBuildDirectory() throws IOException { fileManager.addDirectory(getBuildDir()); - assertEquals(43, fileManager.extractFiles().size()); + assertEquals(50, fileManager.extractFiles().size()); } public void testNonExistentDirectory() { diff --git a/test/jdepend/framework/MetricTest.java b/test/jdepend/framework/MetricTest.java index 150789b..47d5260 100755 --- a/test/jdepend/framework/MetricTest.java +++ b/test/jdepend/framework/MetricTest.java @@ -44,7 +44,7 @@ public void testAnalyzeClassFiles() throws IOException { private void assertAnalyzePackages() { - assertEquals(43, jdepend.countClasses()); + assertEquals(56, jdepend.countClasses()); PackageFilter filter = jdepend.getFilter(); filter.addPackage("junit.*"); @@ -62,13 +62,13 @@ private void assertFrameworkPackage() { JavaPackage p = jdepend.getPackage("jdepend.framework"); assertNotNull(p); - assertEquals(25, p.getConcreteClassCount()); - assertEquals(5, p.getAbstractClassCount()); + assertEquals(29, p.getConcreteClassCount()); + assertEquals(6, p.getAbstractClassCount()); assertEquals(3, p.afferentCoupling()); assertEquals(5, p.efferentCoupling()); assertEquals(format(0.17f), format(p.abstractness())); assertEquals(format(0.62f), format(p.instability())); - assertEquals(format(0.21f), format(p.distance())); + assertEquals(format(0.2f), format(p.distance())); assertEquals(1, p.getVolatility()); } From fbeb5b9f340a35e34e3569fe64ceb55bfecffc2d Mon Sep 17 00:00:00 2001 From: Tom van den Berge Date: Wed, 4 Nov 2015 10:27:08 +0100 Subject: [PATCH 2/2] Added .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ae3c172 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/bin/