Skip to content

Commit 5113aa2

Browse files
authored
Merge pull request #730 from sigstore/string-matcher
Add StringMatchable interface
2 parents c563aaf + 21d977e commit 5113aa2

File tree

3 files changed

+151
-0
lines changed

3 files changed

+151
-0
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright 2024 The Sigstore Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package dev.sigstore.strings;
17+
18+
/** Check exception wrapper around {@link java.util.regex.PatternSyntaxException}. */
19+
public class RegexSyntaxException extends Exception {
20+
public RegexSyntaxException(String message, Throwable cause) {
21+
super(message, cause);
22+
}
23+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright 2024 The Sigstore Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package dev.sigstore.strings;
17+
18+
import java.util.Objects;
19+
import java.util.function.Predicate;
20+
import java.util.regex.Pattern;
21+
import java.util.regex.PatternSyntaxException;
22+
23+
/**
24+
* An interface for allowing direct string matching or regular expressions. Use the static factory
25+
* {@link #string(String)} or {@link #regex(String)} to instantiate the appropriate matcher. Custom
26+
* implementations should override {@link Object#toString} for better error reporting.
27+
*/
28+
public interface StringMatcher extends Predicate<String> {
29+
30+
/** Create a matcher for string equality. */
31+
static StringMatcher string(String string) {
32+
Objects.requireNonNull(string, "string matcher cannot be initialized with null string");
33+
return new StringMatcher() {
34+
@Override
35+
public boolean test(String target) {
36+
return string.equals(target);
37+
}
38+
39+
@Override
40+
public String toString() {
41+
return "'String: " + string + "'";
42+
}
43+
};
44+
}
45+
46+
/**
47+
* Create a matcher using regular expressions. Regex matching ignores null values and returns
48+
* false instead of erroring.
49+
*
50+
* @param string the input pattern
51+
* @return a regex based instance
52+
* @throws RegexSyntaxException if the input pattern is not valid regex. This is a runtime
53+
* exception and probably should be handled
54+
*/
55+
static StringMatcher regex(String string) throws RegexSyntaxException {
56+
Objects.requireNonNull(string, "string matcher cannot be initialized with null regex");
57+
Pattern pattern;
58+
try {
59+
pattern = Pattern.compile(string);
60+
} catch (PatternSyntaxException ex) {
61+
throw new RegexSyntaxException("Could not parse regex: '" + string + "'", ex);
62+
}
63+
return new StringMatcher() {
64+
@Override
65+
public boolean test(String target) {
66+
if (target == null) {
67+
return false;
68+
}
69+
return pattern.matcher(target).matches();
70+
}
71+
72+
@Override
73+
public String toString() {
74+
return "'RegEx: " + pattern + "'";
75+
}
76+
};
77+
}
78+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright 2024 The Sigstore Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package dev.sigstore.strings;
17+
18+
import org.junit.jupiter.api.Assertions;
19+
import org.junit.jupiter.api.Test;
20+
21+
public class StringMatcherTest {
22+
23+
@Test
24+
public void testString() {
25+
var testMatcher = StringMatcher.string("testtest");
26+
Assertions.assertEquals("'String: testtest'", testMatcher.toString());
27+
28+
Assertions.assertTrue(testMatcher.test("testtest"));
29+
Assertions.assertFalse(testMatcher.test("testtest1"));
30+
Assertions.assertFalse(testMatcher.test(""));
31+
Assertions.assertFalse(testMatcher.test(null));
32+
}
33+
34+
@Test
35+
public void testRegex() throws Exception {
36+
var testMatcher = StringMatcher.regex("abc...xyz");
37+
Assertions.assertEquals("'RegEx: abc...xyz'", testMatcher.toString());
38+
39+
Assertions.assertTrue(testMatcher.test("abc888xyz"));
40+
Assertions.assertFalse(testMatcher.test("abc888xyzEXTRA"));
41+
Assertions.assertFalse(testMatcher.test("abcxyz"));
42+
Assertions.assertFalse(testMatcher.test(""));
43+
Assertions.assertFalse(testMatcher.test(null));
44+
}
45+
46+
@Test
47+
public void testRegex_initFailure() {
48+
Assertions.assertThrows(RegexSyntaxException.class, () -> StringMatcher.regex("asdf\\"));
49+
}
50+
}

0 commit comments

Comments
 (0)