Skip to content

Commit 9dc5bdd

Browse files
committed
add + wildcard
1 parent bbb9e2a commit 9dc5bdd

File tree

14 files changed

+165
-103
lines changed

14 files changed

+165
-103
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ public class DependencyTest {
6161

6262
@Override
6363
public void defineRules() {
64-
base().mayUse(util, dep.allSub()); //org.proj may use org.proj.util and all subpackages of org.proj.dep
65-
dep.allSub().mustUse(model); //all subpackages of org.proj.dep must use org.proj.model
64+
base().mayUse(util, dep.allSubOf()); //org.proj may use org.proj.util and all subpackages of org.proj.dep
65+
dep.andAllSub().mustUse(model); //org.proj.dep and all subpackages thereof must use org.proj.model
6666
model.mayUse(util).mustNotUse(base()); //org.proj.model may use org.proj.util but not org.proj
6767
}
6868
}
@@ -333,7 +333,7 @@ public class CodeTest extends CodeAssertJunit5Test {
333333
}
334334
}
335335

336-
final DependencyRules rules = denyAll().withExternals("java*").withRelativeRules(new MyProject());
336+
final DependencyRules rules = denyAll().withExternals("java.*").withRelativeRules(new MyProject());
337337
return new DependencyAnalyzer(CONFIG).rules(rules).analyze();
338338
}
339339

code-assert-gui/src/test/java/guru/nidi/codeassert/gui/CodeTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public void defineRules() {
4747
}
4848

4949
final DependencyRules rules = denyAll()
50-
.withExternals("java*", "org*", "com*")
50+
.withExternals("java.*", "org.*", "com.*")
5151
.withRelativeRules(new GuruNidiCodeassert());
5252
return new DependencyAnalyzer(AnalyzerConfig.maven().main()).rules(rules).analyze();
5353
}

code-assert/src/main/java/guru/nidi/codeassert/config/Location.java

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
import static java.util.Locale.ENGLISH;
2222

2323
public final class Location implements Comparable<Location> {
24-
private static final Pattern CLASS_START = Pattern.compile("(^|\\.)\\*?[A-Z]");
24+
private static final Pattern CLASS_START = Pattern.compile("(^|\\.)[*+]?[A-Z]");
2525

2626
final Language language;
2727
final String pack;
@@ -112,23 +112,21 @@ public Location andMethod(String method) {
112112
}
113113

114114
public String getPattern() {
115+
final boolean noPackEndDot = pack.endsWith("*") || pack.endsWith("+") || pack.length() == 0;
115116
return (language == null ? "" : (language + ":"))
116-
+ (pack.endsWith("*") || pack.length() == 0 || clazz.length() == 0 ? pack : (pack + "."))
117+
+ (noPackEndDot || clazz.length() == 0 ? pack : (pack + "."))
117118
+ clazz
118119
+ (method.length() == 0 ? "" : ("#" + method));
119120
}
120121

121122
private static void checkPattern(String pattern) {
122-
if ("**".equals(pattern)) {
123-
throw new IllegalArgumentException("Wildcard ** is illegal");
123+
if ("**".equals(pattern) || "+*".equals(pattern) || "*+".equals(pattern) || "++".equals(pattern)) {
124+
throw new IllegalArgumentException("Wildcard " + pattern + " is illegal");
124125
}
125-
checkPattern(pattern, pattern.indexOf('*'));
126-
checkPattern(pattern, pattern.lastIndexOf('*'));
127-
}
128-
129-
private static void checkPattern(String pattern, int pos) {
130-
if (pos > 0 && pos != pattern.length() - 1) {
131-
throw new IllegalArgumentException("Wildcard * must be at begin or end of pattern");
126+
for (int i = 0; i < pattern.length(); i++) {
127+
if ((pattern.charAt(i) == '*' || pattern.charAt(i) == '+') && i != 0 && i != pattern.length() - 1) {
128+
throw new IllegalArgumentException("Wildcards must be at begin or end of a pattern");
129+
}
132130
}
133131
}
134132

code-assert/src/main/java/guru/nidi/codeassert/config/LocationMatcher.java

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@
1717

1818
/**
1919
* The LocationMatcher is used to match a code location.
20-
* A pattern has the form [language:][package][[/]class][#method].
21-
* package and class are separated by the first occurrence of \.\*?[A-Z]
22-
* If this is not intended or clear, a / can be used to separate package and class.
23-
* All three elements may start and/or end with a wildcard *.
20+
* A pattern has the form [language:][package][[/]class][#method]. <br>
21+
* package and class are separated by the first occurrence of \.[*+]?[A-Z]
22+
* If this is not intended or clear, a / can be used to separate package and class. <br>
23+
* package, class, method may start and/or end with a wildcard '*' or '+'. <br>
24+
* * means zero or more characters, + means one or more characters,
25+
* .* means zero characters or . followed by one or more characters.
2426
*/
2527
public class LocationMatcher implements Comparable<LocationMatcher> {
2628
private final Location loc;
@@ -69,10 +71,10 @@ private int specificity(String pattern) {
6971
return 1;
7072
}
7173
int s = 4;
72-
if (pattern.startsWith("*")) {
74+
if (pattern.startsWith("*") || pattern.startsWith("+")) {
7375
s--;
7476
}
75-
if (pattern.endsWith("*")) {
77+
if (pattern.endsWith("*") || pattern.endsWith("+")) {
7678
s--;
7779
}
7880
return s;
@@ -98,19 +100,36 @@ private boolean matchesClassPattern(String pat, String name) {
98100
}
99101

100102
static boolean matchesPattern(String pat, String name) {
101-
if (pat.length() == 0) {
103+
if (pat.length() == 0 || "*".equals(pat) || ("+".equals(pat) && name.length() > 0)) {
102104
return true;
103105
}
104-
if (pat.startsWith("*") && pat.endsWith("*")) {
105-
return pat.length() == 1 || name.contains(pat.substring(1, pat.length() - 1));
106+
if (pat.endsWith(".*")) {
107+
return matchesPattern(pat.substring(0, pat.length() - 2), name)
108+
|| matchesPattern(pat.substring(0, pat.length() - 1) + "+", name);
106109
}
107-
if (pat.startsWith("*")) {
108-
return name.endsWith(pat.substring(1));
110+
String pattern = pat;
111+
final char start = pattern.charAt(0);
112+
if (start == '*' || start == '+') {
113+
pattern = pattern.substring(1);
109114
}
110-
if (pat.endsWith("*")) {
111-
return name.startsWith(pat.substring(0, pat.length() - 1));
115+
final char end = pattern.charAt(pattern.length() - 1);
116+
if (end == '*' || end == '+') {
117+
pattern = pattern.substring(0, pattern.length() - 1);
112118
}
113-
return name.equals(pat);
119+
return doMatchesPattern(start, end, pattern, name);
120+
}
121+
122+
private static boolean doMatchesPattern(char start, char end, String pat, String name) {
123+
final int pos = name.indexOf(pat);
124+
if (pos < 0) {
125+
return false;
126+
}
127+
128+
final boolean startsWithPat = pos == 0;
129+
final boolean endsWithPat = pos + pat.length() == name.length();
130+
final boolean startOk = start == '*' || ((start == '+') != startsWithPat);
131+
final boolean endOk = end == '*' || ((end == '+') != endsWithPat);
132+
return startOk && endOk;
114133
}
115134

116135
@Override

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

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,25 +26,29 @@ public class CodeElement implements UsingElementMatcher {
2626

2727
CodeElement(String pattern, boolean allowAll) {
2828
final int starPos = pattern.indexOf('*');
29-
if (starPos >= 0 && starPos != pattern.length() - 1) {
30-
throw new IllegalArgumentException("Wildcard * is only allowed at the end (e.g. java*)");
29+
final int plusPos = pattern.indexOf('+');
30+
if ((starPos >= 0 && starPos != pattern.length() - 1) || (plusPos >= 0 && plusPos != pattern.length() - 1)) {
31+
throw new IllegalArgumentException("Wildcards are allowed at the end (e.g. java.*)");
3132
}
3233
this.pattern = new LocationMatcher(Location.of(pattern));
3334
this.allowAll = allowAll;
3435
}
3536

36-
public DependencyRule allSub() {
37-
final String newPattern = pattern.toString() + (pattern.toString().endsWith(".") ? "*" : ".*");
38-
return DependencyRules.addRuleToCurrent(new DependencyRule(newPattern, allowAll));
37+
public DependencyRule andAllSub() {
38+
return sub("*");
39+
}
40+
41+
public DependencyRule allSubOf() {
42+
return sub("+");
3943
}
4044

4145
public DependencyRule sub(String name) {
42-
final String newPattern = pattern.getPattern() + "." + name;
46+
final String newPattern = pattern.toString() + (pattern.toString().endsWith(".") ? "" : ".") + name;
4347
return DependencyRules.addRuleToCurrent(new DependencyRule(newPattern, allowAll));
4448
}
4549

4650
public DependencyRule rule() {
47-
final String newPattern = pattern.getPattern();
51+
final String newPattern = pattern.toString();
4852
return DependencyRules.addRuleToCurrent(new DependencyRule(newPattern, allowAll));
4953
}
5054

code-assert/src/test/java/guru/nidi/codeassert/EatYourOwnDogfoodTest.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@
1616
package guru.nidi.codeassert;
1717

1818
import guru.nidi.codeassert.checkstyle.*;
19-
import guru.nidi.codeassert.config.AnalyzerConfig;
20-
import guru.nidi.codeassert.config.In;
19+
import guru.nidi.codeassert.config.*;
2120
import guru.nidi.codeassert.dependency.*;
2221
import guru.nidi.codeassert.findbugs.*;
2322
import guru.nidi.codeassert.jacoco.Coverage;
@@ -46,7 +45,7 @@ public void defineRules() {
4645
}
4746

4847
final DependencyRules rules = denyAll()
49-
.withExternals("edu*", "java*", "net*", "org*", "com*", "kotlin*", "io*")
48+
.withExternals("edu.*", "java.*", "net.*", "org.*", "com.*", "kotlin.*", "io.*")
5049
.withRelativeRules(new GuruNidiCodeassert());
5150
return new DependencyAnalyzer(AnalyzerConfig.maven().main()).rules(rules).analyze();
5251
}
@@ -80,7 +79,9 @@ protected PmdResult analyzePmd() {
8079
In.clazz(PmdRulesets.class).ignore("TooManyMethods", "AvoidDuplicateLiterals"),
8180
In.classes("Reason").ignore("SingularField"),
8281
In.clazz(Coverage.class).ignore("ExcessiveParameterList"),
83-
In.classes("SourceFileParser").ignore("CyclomaticComplexity", "ModifiedCyclomaticComplexity", "StdCyclomaticComplexity"),
82+
In.clazz(LocationMatcher.class).ignore("GodClass"),
83+
In.classes("SourceFileParser", "Location", "LocationMatcher")
84+
.ignore("CyclomaticComplexity", "ModifiedCyclomaticComplexity", "StdCyclomaticComplexity"),
8485
In.classes("DependencyRules", "CodeClassBuilder").ignore("GodClass"));
8586
return new PmdAnalyzer(AnalyzerConfig.maven().main(), collector)
8687
.withRulesets(PredefConfig.defaultPmdRulesets())

code-assert/src/test/java/guru/nidi/codeassert/checkstyle/CheckstyleTest.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import guru.nidi.codeassert.snippets.DependencyTest;
2525
import org.hamcrest.Matcher;
2626
import org.hamcrest.StringDescription;
27-
import org.junit.jupiter.api.BeforeAll;
2827
import org.junit.jupiter.api.Test;
2928

3029
import java.io.File;
@@ -44,13 +43,9 @@ public class CheckstyleTest {
4443

4544
private final AnalyzerConfig config = AnalyzerConfig.maven().mainAndTest();
4645

47-
@BeforeAll
48-
static void init() {
49-
Locale.setDefault(Locale.ENGLISH);
50-
}
51-
5246
@Test
5347
void google() {
48+
Locale.setDefault(Locale.ENGLISH);
5449
final CheckstyleAnalyzer analyzer = new CheckstyleAnalyzer(config, StyleChecks.google()
5550
.maxLineLen(120).indentBasic(4).indentCase(4)
5651
.paramName("^[a-z][a-zA-Z0-9]*$")
@@ -82,6 +77,7 @@ void google() {
8277

8378
@Test
8479
void sun() {
80+
Locale.setDefault(Locale.ENGLISH);
8581
final CheckstyleAnalyzer analyzer = new CheckstyleAnalyzer(config, StyleChecks.sun()
8682
.maxLineLen(120).allowDefaultAccessMembers(true),
8783
new StyleEventCollector().severity(WARNING).config(

0 commit comments

Comments
 (0)