-
Notifications
You must be signed in to change notification settings - Fork 4
feat(assertion): Add RegularExpressionValueComparer #974
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
144 changes: 144 additions & 0 deletions
144
src/main/java/org/dbunit/assertion/comparer/value/RegularExpressionValueComparer.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,144 @@ | ||
| package org.dbunit.assertion.comparer.value; | ||
|
|
||
| import java.util.regex.Matcher; | ||
| import java.util.regex.Pattern; | ||
| import java.util.regex.PatternSyntaxException; | ||
|
|
||
| import org.dbunit.DatabaseUnitException; | ||
| import org.dbunit.dataset.ITable; | ||
| import org.dbunit.dataset.datatype.DataType; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
| /** | ||
| * {@link ValueComparer} implementation that verifies the actual value matches | ||
| * the regular expression supplied as the expected value. | ||
| * | ||
| * <p> | ||
| * The expected value, converted to a {@link String}, is the | ||
| * {@link java.util.regex.Pattern regular expression}; the actual value, also | ||
| * converted to a {@link String}, is the input tested against it. This mirrors | ||
| * how {@link IsActualContainingExpectedStringValueComparer} treats the expected | ||
| * value as the substring to look for. | ||
| * | ||
| * <p> | ||
| * The comparison succeeds only when the pattern matches the <em>entire</em> | ||
| * actual value, using {@link Matcher#matches()}, consistent with | ||
| * {@link String#matches(String)}. To match only part of the actual value, make | ||
| * the pattern permissive at both ends, for example <code>.*[0-9]{4}.*</code>. | ||
| * A <code>.</code> does not match a line terminator unless the | ||
| * {@link Pattern#DOTALL DOTALL} flag is set, so prefix such a pattern with | ||
| * <code>(?s)</code> when the actual value may contain a newline, for example | ||
| * <code>(?s).*[0-9]{4}.*</code>. | ||
| * | ||
| * <p> | ||
| * Useful for columns whose exact content a test does not control but whose | ||
| * format it does, such as database-generated identifiers, UUID columns, or | ||
| * timestamps rendered into a text column. | ||
| * | ||
| * <p> | ||
| * Special case: if both values are null, they match; if exactly one is null, | ||
| * they do not. | ||
| * | ||
| * <p> | ||
| * This comparer adds no dependency beyond {@code java.util.regex}, so it is also | ||
| * available as {@link ValueComparers#regularExpressionValueComparer}. | ||
| * | ||
| * @author Jeff Jensen | ||
| * @since 3.6.0 | ||
| */ | ||
| public class RegularExpressionValueComparer extends ValueComparerTemplateBase | ||
| { | ||
| private final Logger log = LoggerFactory.getLogger(getClass()); | ||
|
|
||
| @Override | ||
| protected boolean isExpected(final ITable expectedTable, | ||
| final ITable actualTable, final int rowNum, final String columnName, | ||
| final DataType dataType, final Object expectedValue, | ||
| final Object actualValue) throws DatabaseUnitException | ||
| { | ||
| final boolean isExpected; | ||
|
|
||
| // handle nulls: prevent NPE and isExpected=true when both null | ||
| if (expectedValue == null && actualValue == null) | ||
| { | ||
| // both are null, so match | ||
| isExpected = true; | ||
| } else if (expectedValue == null || actualValue == null) | ||
| { | ||
| // both aren't null, one is null, so no match | ||
| isExpected = false; | ||
| } else | ||
| { | ||
| // neither are null, so compare | ||
| isExpected = isMatching(rowNum, columnName, expectedValue, | ||
| actualValue); | ||
| } | ||
|
|
||
| return isExpected; | ||
| } | ||
|
|
||
| /** | ||
| * Returns whether the regular expression held in the expected value matches | ||
| * the whole actual value, both converted to strings. | ||
| * | ||
| * @param rowNum | ||
| * The current row number comparing, used only to identify an | ||
| * invalid pattern. | ||
| * @param columnName | ||
| * The name of the current column comparing, used only to identify | ||
| * an invalid pattern. | ||
| * @param expectedValue | ||
| * The expected value, holding the regular expression. | ||
| * @param actualValue | ||
| * The actual value tested against the regular expression. | ||
| * @return <code>true</code> if the regular expression matches the entire | ||
| * actual value string. | ||
| * @throws DatabaseUnitException | ||
| * If either value cannot be converted to a string, or the | ||
| * expected value is not a valid regular expression. | ||
| */ | ||
| protected boolean isMatching(final int rowNum, final String columnName, | ||
| final Object expectedValue, final Object actualValue) | ||
| throws DatabaseUnitException | ||
| { | ||
| final String regex = DataType.asString(expectedValue); | ||
| final String actualValueString = DataType.asString(actualValue); | ||
| final Pattern pattern = compilePattern(rowNum, columnName, regex); | ||
| final Matcher matcher = pattern.matcher(actualValueString); | ||
| final boolean isMatching = matcher.matches(); | ||
| log.debug("isMatching: regex={}, actualValueString={}, isMatching={}", | ||
| regex, actualValueString, isMatching); | ||
|
|
||
| return isMatching; | ||
| } | ||
|
|
||
| /** | ||
| * Compiles the expected value into a {@link Pattern}, turning an invalid | ||
| * expression into a {@link DatabaseUnitException} identifying the row and | ||
| * column, consistent with how | ||
| * {@link IsActualEqualToExpectedJsonValueComparer} reports an unparseable | ||
| * expected value. | ||
| */ | ||
| private Pattern compilePattern(final int rowNum, final String columnName, | ||
| final String regex) throws DatabaseUnitException | ||
| { | ||
| try | ||
| { | ||
| return Pattern.compile(regex); | ||
| } catch (final PatternSyntaxException e) | ||
| { | ||
| final String message = String.format( | ||
| "Unable to compile expected value as a regular expression" | ||
| + " for column '%s', row %d: %s", | ||
| columnName, rowNum, regex); | ||
| throw new DatabaseUnitException(message, e); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| protected String getFailPhrase() | ||
| { | ||
| return "not matching the regular expression"; | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.