mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-11-26 06:12:06 +01:00
Add support for different regex parsers
This commit is contained in:
parent
3f10efac7a
commit
21f8ba8ccf
8 changed files with 270 additions and 1 deletions
28
hsregex/build.gradle
Normal file
28
hsregex/build.gradle
Normal file
|
@ -0,0 +1,28 @@
|
|||
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
plugins {
|
||||
id 'java-library'
|
||||
}
|
||||
|
||||
group 'org.pgpainless'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion"
|
||||
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion"
|
||||
|
||||
implementation(project(":pgpainless-core"))
|
||||
|
||||
// Henry Spencers Regular Expression (RegEx packets)
|
||||
implementation 'com.basistech.tclre:tcl-regex:0.14.5'
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package org.pgpainless.algorithm;
|
||||
|
||||
import com.basistech.tclre.HsrePattern;
|
||||
import com.basistech.tclre.PatternFlags;
|
||||
import com.basistech.tclre.RePattern;
|
||||
import com.basistech.tclre.RegexException;
|
||||
|
||||
public class HSRegexInterpreterFactory extends RegexInterpreterFactory {
|
||||
|
||||
public Regex instantiate(String regex) {
|
||||
return new Regex() {
|
||||
|
||||
private final RePattern pattern;
|
||||
|
||||
{
|
||||
try {
|
||||
pattern = HsrePattern.compile(regex, PatternFlags.ADVANCED);
|
||||
} catch (RegexException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(String string) {
|
||||
return pattern.matcher(string).find();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/**
|
||||
* Regex interpreter implementation based on Henry Spencers Regular Expression library.
|
||||
*
|
||||
* @see <a href="https://www.rfc-editor.org/rfc/rfc4880#section-8">RFC4880 - §8. Regular Expressions</a>
|
||||
*/
|
||||
package org.pgpainless.algorithm;
|
|
@ -30,4 +30,7 @@ dependencies {
|
|||
|
||||
// @Nullable, @Nonnull annotations
|
||||
implementation "com.google.code.findbugs:jsr305:3.0.2"
|
||||
|
||||
// HSRE regex for tests
|
||||
testImplementation project(":hsregex")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package org.pgpainless.algorithm;
|
||||
|
||||
import org.pgpainless.key.util.UserId;
|
||||
|
||||
public interface Regex {
|
||||
|
||||
/**
|
||||
* Return true, if the regex matches the given user-id.
|
||||
*
|
||||
* @param userId userId
|
||||
* @return true if matches, false otherwise
|
||||
*/
|
||||
default boolean matches(UserId userId) {
|
||||
return matches(userId.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true, if the regex matches the given string.
|
||||
*
|
||||
* @param string string
|
||||
* @return true if matches, false otherwise
|
||||
*/
|
||||
boolean matches(String string);
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package org.pgpainless.algorithm;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public abstract class RegexInterpreterFactory {
|
||||
|
||||
private static RegexInterpreterFactory INSTANCE;
|
||||
|
||||
public static RegexInterpreterFactory getInstance() {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = new JavaRegexInterpreterFactory();
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public static void setInstance(@Nonnull RegexInterpreterFactory instance) {
|
||||
INSTANCE = instance;
|
||||
}
|
||||
|
||||
public static Regex create(String regex) {
|
||||
return getInstance().instantiate(regex);
|
||||
}
|
||||
|
||||
public abstract Regex instantiate(String regex) throws IllegalArgumentException;
|
||||
|
||||
public static class JavaRegexInterpreterFactory extends RegexInterpreterFactory {
|
||||
|
||||
@Override
|
||||
public Regex instantiate(String regex) {
|
||||
return new Regex() {
|
||||
|
||||
private final Pattern pattern = Pattern.compile(regex);
|
||||
|
||||
@Override
|
||||
public boolean matches(String string) {
|
||||
return pattern.matcher(string).find();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package org.pgpainless.algorithm;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.jupiter.api.Named;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.pgpainless.key.util.UserId;
|
||||
|
||||
public class RegexTest {
|
||||
private static Stream<Arguments> provideRegexInterpreterFactories() {
|
||||
return Stream.of(
|
||||
Arguments.of(Named.of("Default JavaRegexInterpreterFactory",
|
||||
new RegexInterpreterFactory.JavaRegexInterpreterFactory())),
|
||||
Arguments.of(Named.of("HSRegexInterpreterFactory",
|
||||
new HSRegexInterpreterFactory()))
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideRegexInterpreterFactories")
|
||||
public void simpleTest(RegexInterpreterFactory factory) {
|
||||
Regex regex = factory.instantiate("Alice|Bob");
|
||||
assertTrue(regex.matches("Alice"));
|
||||
assertTrue(regex.matches("Bob"));
|
||||
assertFalse(regex.matches("Charlie"));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideRegexInterpreterFactories")
|
||||
public void testEmailRegexMatchesDomain(RegexInterpreterFactory factory) {
|
||||
Regex regex = factory.instantiate("<[^>]+[@.]pgpainless\\.org>$");
|
||||
assertTrue(regex.matches("Alice <alice@pgpainless.org>"));
|
||||
assertTrue(regex.matches("Bob <bob@pgpainless.org>"));
|
||||
assertFalse(regex.matches("Alice <alice@example.com>"), "wrong domain");
|
||||
assertFalse(regex.matches("Bob <bob@example.com>"), "wrong domain");
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideRegexInterpreterFactories")
|
||||
public void testEmailRegexMatchesOnlyWrappedAddresses(RegexInterpreterFactory factory) {
|
||||
Regex regex = factory.instantiate("<[^>]+[@.]pgpainless\\.org>$");
|
||||
assertTrue(regex.matches("<alice@pgpainless.org>"));
|
||||
assertFalse(regex.matches("alice@pgpainless.org"), "only match mails in <>");
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideRegexInterpreterFactories")
|
||||
public void testCaseSensitivity(RegexInterpreterFactory factory) {
|
||||
Regex regex = factory.instantiate("<[^>]+[@.]pgpainless\\.org>$");
|
||||
assertFalse(regex.matches("Alice <alice@PGPAINLESS.ORG>"));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideRegexInterpreterFactories")
|
||||
public void testWildCard(RegexInterpreterFactory factory) {
|
||||
Regex regex = factory.instantiate(".*");
|
||||
assertTrue(regex.matches(""));
|
||||
assertTrue(regex.matches("Alice"));
|
||||
assertTrue(regex.matches("<alice@pgpainless.org>"));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideRegexInterpreterFactories")
|
||||
public void testExclusion(RegexInterpreterFactory factory) {
|
||||
// Test [^>] matches all but '>'
|
||||
Regex regex = factory.instantiate("<[^>]+[@.]pgpainless\\.org>$");
|
||||
assertFalse(regex.matches("<alice>appendix@pgpainless.org>"));
|
||||
assertFalse(regex.matches("<>alice@pgpainless.org>"));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideRegexInterpreterFactories")
|
||||
public void testOnlyMatchAtTheEnd(RegexInterpreterFactory factory) {
|
||||
Regex regex = factory.instantiate("<[^>]+[@.]pgpainless\\.org>$");
|
||||
assertFalse(regex.matches("Alice <alice@pgpainless.org><bob@example.org>"));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideRegexInterpreterFactories")
|
||||
public void testRanges(RegexInterpreterFactory factory) {
|
||||
Regex regex = factory.instantiate("<[^>]+[0-9][@.]pgpainless\\.org>$");
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
String mail = "<user" + i + "@pgpainless.org>";
|
||||
assertTrue(regex.matches(mail));
|
||||
}
|
||||
|
||||
assertFalse(regex.matches("<user@pgpainless.org>"));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideRegexInterpreterFactories")
|
||||
public void testExactMailMatch(RegexInterpreterFactory factory) {
|
||||
Regex exactMail = factory.instantiate("<exact@pgpainless\\.org>$");
|
||||
assertTrue(exactMail.matches("<exact@pgpainless.org>"));
|
||||
assertTrue(exactMail.matches("Exact Match <exact@pgpainless.org>"));
|
||||
assertFalse(exactMail.matches("<roughly-exact@pgpainless.org>"));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideRegexInterpreterFactories")
|
||||
public void testSetInstance(RegexInterpreterFactory factory) {
|
||||
RegexInterpreterFactory before = RegexInterpreterFactory.getInstance();
|
||||
RegexInterpreterFactory.setInstance(factory);
|
||||
|
||||
Regex regex = RegexInterpreterFactory.create("<[^>]+[@.]pgpainless\\.org>$");
|
||||
assertTrue(regex.matches(UserId.nameAndEmail("Alice", "alice@pgpainless.org")));
|
||||
|
||||
RegexInterpreterFactory.setInstance(before);
|
||||
}
|
||||
}
|
|
@ -6,5 +6,6 @@ rootProject.name = 'PGPainless'
|
|||
|
||||
include 'pgpainless-core',
|
||||
'pgpainless-sop',
|
||||
'pgpainless-cli'
|
||||
'pgpainless-cli',
|
||||
'hsregex'
|
||||
|
||||
|
|
Loading…
Reference in a new issue