Skip to content

Commit 3fb3646

Browse files
committed
more work on ModelVisualizer
1 parent b70c1e3 commit 3fb3646

File tree

7 files changed

+127
-42
lines changed

7 files changed

+127
-42
lines changed

code-assert/images/packages.png

16.1 KB
Loading

code-assert/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@
8989
<dependency>
9090
<groupId>guru.nidi</groupId>
9191
<artifactId>graphviz-java</artifactId>
92-
<version>0.8.3</version>
92+
<version>0.8.4</version>
9393
</dependency>
9494
<dependency>
9595
<groupId>org.hamcrest</groupId>

code-assert/src/main/java/guru/nidi/codeassert/dependency/Dependencies.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
import guru.nidi.codeassert.config.LocationMatcher;
1919

2020
import java.util.*;
21+
import java.util.function.Function;
22+
import java.util.stream.StreamSupport;
23+
24+
import static java.util.stream.Collectors.toList;
2125

2226
public class Dependencies {
2327
final DependencyMap allowed;
@@ -81,6 +85,16 @@ public Set<DependencyMap> getCycles() {
8185
return cycles;
8286
}
8387

88+
public boolean isDenied(String from, String to) {
89+
return denied.getDependency(from, to) != null;
90+
}
91+
92+
public <T> List<String> getMissing(String from, Iterable<T> to, Function<T, String> toPack) {
93+
return missing.getDependencies(from).keySet().stream().filter(miss ->
94+
StreamSupport.stream(to.spliterator(), false).noneMatch(p -> toPack.apply(p).equals(miss))
95+
).collect(toList());
96+
}
97+
8498
@Override
8599
public boolean equals(Object o) {
86100
if (this == o) {

code-assert/src/main/java/guru/nidi/codeassert/dependency/DependencyMap.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121
import java.util.*;
2222
import java.util.Map.Entry;
2323

24-
class DependencyMap {
24+
import static java.util.Collections.emptyMap;
25+
26+
public class DependencyMap {
2527
private final Map<String, Map<String, Info>> map = new LinkedHashMap<>();
2628

2729
public <T> void with(int specificity, UsingElement<T> from, UsingElement<T> to) {
@@ -101,7 +103,11 @@ public Set<String> getElements() {
101103
* Key: package, Value: A set of all classes importing the package
102104
*/
103105
public Map<String, Info> getDependencies(String name) {
104-
return map.get(name);
106+
return map.getOrDefault(name, emptyMap());
107+
}
108+
109+
public Info getDependency(String from, String to) {
110+
return getDependencies(from).get(to);
105111
}
106112

107113
@Override

code-assert/src/main/java/guru/nidi/codeassert/io/ModelVisualizer.java

Lines changed: 27 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -15,75 +15,66 @@
1515
*/
1616
package guru.nidi.codeassert.io;
1717

18-
import guru.nidi.codeassert.config.For;
19-
import guru.nidi.codeassert.jacoco.*;
20-
import guru.nidi.codeassert.model.*;
21-
import guru.nidi.graphviz.attribute.*;
18+
import guru.nidi.codeassert.model.CodePackage;
19+
import guru.nidi.codeassert.model.Model;
20+
import guru.nidi.graphviz.attribute.RankDir;
2221
import guru.nidi.graphviz.engine.Graphviz;
2322
import guru.nidi.graphviz.model.*;
2423

25-
import java.util.Map;
2624
import java.util.function.Function;
2725

28-
import static guru.nidi.codeassert.config.CollectorConfig.just;
2926
import static guru.nidi.graphviz.model.Factory.mutGraph;
30-
import static guru.nidi.graphviz.model.Factory.mutNode;
31-
import static java.util.stream.Collectors.toMap;
3227

3328
public class ModelVisualizer {
3429
private final Model model;
35-
private final Function<CodePackage, String> labelFunc;
30+
private final Function<String, String> labelFunc;
3631

3732
public ModelVisualizer(Model model) {
38-
this(model, CodePackage::getName);
33+
this(model, n -> n);
3934
}
4035

41-
public ModelVisualizer(Model model, Function<CodePackage, String> labelFunc) {
36+
public ModelVisualizer(Model model, Function<String, String> labelFunc) {
4237
this.model = model;
4338
this.labelFunc = labelFunc;
4439
}
4540

46-
public ModelVisualizer labelFunc(Function<CodePackage, String> labelFunc) {
41+
public ModelVisualizer labelFunc(Function<String, String> labelFunc) {
4742
return new ModelVisualizer(model, labelFunc);
4843
}
4944

50-
public Visualized visualize() {
51-
final Map<String, Double> coverage = new JacocoAnalyzer(new CoverageCollector(CoverageType.LINE)
52-
.config(just(For.allPackages().setMinima(100))))
53-
.analyze()
54-
.findings().stream()
55-
.collect(toMap(f -> f.getPack(), f -> f.getValues()[0]));
45+
public Visualized visualizePackages(Function<CodePackage, MutableNode> transform) {
5646
final MutableGraph graph = CreationContext.use(ctx -> {
5747
final MutableGraph g = mutGraph().setDirected(true)
5848
.graphAttrs().add(RankDir.LEFT_TO_RIGHT);
5949
for (CodePackage pack : model.getPackages()) {
60-
final MutableNode source = mutNode(labelFunc.apply(pack)).add(Shape.ELLIPSE);
61-
if (model.isOwnPackage(pack)) {
62-
final Double cover = coverage.getOrDefault(pack.getName(), 1D);
63-
final int codeSize = pack.getClasses().stream().mapToInt(CodeClass::getTotalSize).sum();
64-
source.add(Shape.RECTANGLE)
65-
.add(Size.mode(Size.Mode.FIXED))
66-
.add("height", .5 + pack.getClasses().size() / 10.0)
67-
.add("width", 1 + codeSize / 20000.0)
68-
.add(Color.rgb(255 - (int) (2.55 * cover), (int) (2.55 * cover) - 255, 0).fill())
69-
.add(Style.FILLED);
70-
}
71-
g.add(source);
72-
for (CodePackage dep : pack.uses()) {
73-
source.addLink(labelFunc.apply(dep));
74-
}
50+
g.add(transform.apply(pack));
7551
}
52+
53+
// for (CodeClass clazz : model.getClasses()) {
54+
// final MutableNode source = mutNode(clazz.getSimpleName()).add(Shape.ELLIPSE);
55+
// if (model.isOwnPackage(clazz.getPackage())) {
56+
// final Double cover = coverage.getOrDefault(clazz.getName(), 1D);
57+
// source.add(Shape.RECTANGLE)
58+
// .add(Size.mode(FIXED).size(1 + clazz.getTotalSize() / 5000.0, 1))
59+
// .add(Color.rgb(255 - (int) (2.55 * cover), (int) (2.55 * cover) - 255, 0).fill())
60+
// .add(Style.FILLED);
61+
// }
62+
// g.add(source);
63+
// for (CodeClass dep : clazz.uses()) {
64+
// source.addLink(dep.getSimpleName());
65+
// }
66+
// }
67+
7668
return g;
7769
});
7870
return new Visualized(Graphviz.fromGraph(graph));
7971
}
8072

81-
public static Function<CodePackage, String> replaceFunc(String... replacements) {
73+
public static Function<String, String> replaceFunc(String... replacements) {
8274
if (replacements.length % 2 != 0) {
8375
throw new IllegalArgumentException("An even number of replacement parameters expected.");
8476
}
85-
return codePackage -> {
86-
final String name = codePackage.getName();
77+
return name -> {
8778
for (int i = 0; i < replacements.length; i += 2) {
8879
if (name.startsWith(replacements[i])) {
8980
return replacements[i + 1] + name.substring(replacements[i].length());

code-assert/src/main/java/guru/nidi/codeassert/model/CodeClass.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ public String getName() {
6060
return name;
6161
}
6262

63+
public String getSimpleName() {
64+
return name.substring(pack.getName().length() + 1);
65+
}
66+
6367
public CodePackage getPackage() {
6468
return pack;
6569
}

code-assert/src/test/java/guru/nidi/codeassert/io/ModelVisualizerTest.java

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,27 @@
1616
package guru.nidi.codeassert.io;
1717

1818
import guru.nidi.codeassert.config.AnalyzerConfig;
19-
import guru.nidi.codeassert.model.Model;
19+
import guru.nidi.codeassert.config.For;
20+
import guru.nidi.codeassert.dependency.*;
21+
import guru.nidi.codeassert.jacoco.*;
22+
import guru.nidi.codeassert.model.*;
23+
import guru.nidi.graphviz.attribute.*;
24+
import guru.nidi.graphviz.model.MutableNode;
2025
import org.junit.jupiter.api.Disabled;
2126
import org.junit.jupiter.api.Test;
2227

2328
import java.io.File;
2429
import java.io.IOException;
30+
import java.util.Map;
31+
import java.util.function.Function;
2532

33+
import static guru.nidi.codeassert.config.CollectorConfig.just;
34+
import static guru.nidi.codeassert.dependency.DependencyRules.denyAll;
2635
import static guru.nidi.codeassert.io.ModelVisualizer.replaceFunc;
36+
import static guru.nidi.graphviz.attribute.Size.Mode.FIXED;
37+
import static guru.nidi.graphviz.model.Factory.mutNode;
38+
import static guru.nidi.graphviz.model.Factory.to;
39+
import static java.util.stream.Collectors.toMap;
2740
import static org.junit.jupiter.api.Assertions.assertTrue;
2841

2942
class ModelVisualizerTest {
@@ -35,9 +48,66 @@ void myself() throws IOException {
3548
.ignoringPackages("java", "org.hamcrest", "org.slf4j", "org.apache")
3649
.mergingPackages("edu.umd.cs.findbugs", "net.sourceforge.pmd", "io.gitlab.arturbosch.detekt", "com.puppycrawl.tools.checkstyle", "com.github.shyiko.ktlint", "kotlin", "org.junit", "guru.nidi.graphviz")
3750
.read();
38-
final ModelVisualizer visualizer = new ModelVisualizer(model).labelFunc(replaceFunc("guru.nidi.codeassert", ""));
51+
52+
class GuruNidiCodeassert extends DependencyRuler {
53+
DependencyRule checkstyleLib = denyRule("com.puppycrawl.tools.checkstyle").andAllSub();
54+
DependencyRule detektLib = denyRule("io.gitlab.arturbosch.detekt").andAllSub();
55+
DependencyRule findBugsLib = denyRule("edu.umd.cs.findbugs").andAllSub();
56+
DependencyRule ktlintLib = denyRule("com.github.shyiko.ktlint").andAllSub();
57+
DependencyRule pmdLib = denyRule("net.sourceforge.pmd").andAllSub();
58+
DependencyRule graphvizLib = denyRule("guru.nidi.graphviz").andAllSub();
59+
DependencyRule config, dependency, findbugs, checkstyle, detekt, io, model, pmd, ktlint, util, junit, junitKotlin, jacoco;
60+
61+
@Override
62+
public void defineRules() {
63+
base().mayBeUsedBy(all());
64+
config.mayBeUsedBy(all());
65+
util.mayBeUsedBy(all());
66+
dependency.mayUse(model);
67+
junit.mayUse(model, dependency, findbugs, checkstyle, pmd);
68+
junitKotlin.mayUse(ktlint, detekt);
69+
checkstyle.mayUse(checkstyleLib);
70+
detekt.mayUse(detektLib);
71+
findbugs.mayUse(findBugsLib);
72+
io.mayUse(jacoco, model, graphvizLib);
73+
ktlint.mayUse(ktlintLib);
74+
pmd.mayUse(pmdLib).mustUse(io);
75+
}
76+
}
77+
78+
final DependencyRules rules = denyAll()
79+
.withExternals("java.*", "org.*", "kotlin.*")
80+
.withRelativeRules(new GuruNidiCodeassert());
81+
final Dependencies dependencies = new DependencyAnalyzer(model).rules(rules).analyze().findings();
82+
83+
final Map<String, Double> coverage = new JacocoAnalyzer(new CoverageCollector(CoverageType.LINE)
84+
.config(just(For.allPackages().setMinima(100))))
85+
.analyze()
86+
.findings().stream()
87+
.collect(toMap(f -> f.getPack(), f -> f.getValues()[0]));
88+
89+
final Function<String, String> labelFunc = replaceFunc("guru.nidi.codeassert", "");
90+
final ModelVisualizer visualizer = new ModelVisualizer(model).labelFunc(labelFunc);
3991
final File target = new File("images/packages.png");
40-
visualizer.visualize().toFile(target);
92+
visualizer.visualizePackages(pack -> {
93+
final MutableNode node = mutNode(labelFunc.apply(pack.getName())).add(Shape.ELLIPSE);
94+
if (model.isOwnPackage(pack)) {
95+
final Double cover = coverage.getOrDefault(pack.getName(), 1D);
96+
final int codeSize = pack.getClasses().stream().mapToInt(CodeClass::getTotalSize).sum();
97+
node.add(Shape.RECTANGLE)
98+
.add(Size.mode(FIXED).size(1 + codeSize / 20000.0, .5 + pack.getClasses().size() / 10.0))
99+
.add(Color.rgb(255 - (int) (2.55 * cover), (int) (2.55 * cover) - 255, 0).fill())
100+
.add(Style.FILLED);
101+
}
102+
for (String missing : dependencies.getMissing(pack.getName(), pack.uses(), CodePackage::getName)) {
103+
node.addLink(to(mutNode(labelFunc.apply(missing))).with(Style.DASHED, Color.RED));
104+
}
105+
for (CodePackage dep : pack.uses()) {
106+
final boolean denied = dependencies.isDenied(pack.getName(), dep.getName());
107+
node.addLink(to(mutNode(labelFunc.apply(dep.getName()))).with(denied ? Color.RED : Color.BLACK));
108+
}
109+
return node;
110+
}).toFile(target);
41111
assertTrue(target.exists());
42112
}
43113
}

0 commit comments

Comments
 (0)