From 06ab16e2f61b0d30302e645be386ce02c26086b4 Mon Sep 17 00:00:00 2001 From: gmungoc Date: Mon, 13 Apr 2020 12:45:38 +0100 Subject: [PATCH] JAL-3574 Matcher with integer/long value pattern (e.g. VCF POS locus) --- src/jalview/util/matcher/Matcher.java | 243 +++++++++++++++----- src/jalview/util/matcher/MatcherI.java | 2 - .../datamodel/features/FeatureMatcherTest.java | 74 +++--- test/jalview/gui/FeatureSettingsTest.java | 16 +- test/jalview/io/FeaturesFileTest.java | 27 +-- test/jalview/project/Jalview2xmlTests.java | 32 +-- test/jalview/util/matcher/MatcherTest.java | 178 ++++++++++++-- 7 files changed, 426 insertions(+), 146 deletions(-) diff --git a/src/jalview/util/matcher/Matcher.java b/src/jalview/util/matcher/Matcher.java index 0792509..bdf3aa7 100644 --- a/src/jalview/util/matcher/Matcher.java +++ b/src/jalview/util/matcher/Matcher.java @@ -1,39 +1,49 @@ package jalview.util.matcher; import java.util.Objects; -import java.util.regex.Pattern; /** * A bean to describe one attribute-based filter */ public class Matcher implements MatcherI { + public enum PatternType + { + String, Integer, Float + } + /* * the comparison condition */ - Condition condition; + private final Condition condition; /* - * the string pattern as entered, or the regex, to compare to - * also holds the string form of float value if a numeric condition + * the string pattern as entered, to compare to */ - String pattern; + private String pattern; /* * the pattern in upper case, for non-case-sensitive matching */ - String uppercasePattern; + private final String uppercasePattern; /* * the compiled regex if using a pattern match condition - * (reserved for possible future enhancement) + * (possible future enhancement) */ - Pattern regexPattern; + // private Pattern regexPattern; /* - * the value to compare to for a numerical condition + * the value to compare to for a numerical condition with a float pattern */ - float value; + private float floatValue = 0F; + + /* + * the value to compare to for a numerical condition with an integer pattern + */ + private long longValue = 0L; + + private PatternType patternType; /** * Constructor @@ -51,30 +61,38 @@ public class Matcher implements MatcherI { Objects.requireNonNull(cond); condition = cond; + if (cond.isNumeric()) { - value = Float.valueOf(compareTo); - pattern = String.valueOf(value); - uppercasePattern = pattern; + try + { + longValue = Long.valueOf(compareTo); + pattern = String.valueOf(longValue); + patternType = PatternType.Integer; + } catch (NumberFormatException e) + { + floatValue = Float.valueOf(compareTo); + pattern = String.valueOf(floatValue); + patternType = PatternType.Float; + } } else { pattern = compareTo; - if (pattern != null) - { - uppercasePattern = pattern.toUpperCase(); - } + patternType = PatternType.String; } + uppercasePattern = pattern == null ? null : pattern.toUpperCase(); + // if we add regex conditions (e.g. matchesPattern), then // pattern should hold the raw regex, and // regexPattern = Pattern.compile(compareTo); } /** - * Constructor for a numerical match condition. Note that if a string - * comparison condition is specified, this will be converted to a comparison - * with the float value as string + * Constructor for a float-valued numerical match condition. Note that if a + * string comparison condition is specified, this will be converted to a + * comparison with the float value as string * * @param cond * @param compareTo @@ -85,39 +103,56 @@ public class Matcher implements MatcherI } /** + * Constructor for an integer-valued numerical match condition. Note that if a + * string comparison condition is specified, this will be converted to a + * comparison with the integer value as string + * + * @param cond + * @param compareTo + */ + public Matcher(Condition cond, long compareTo) + { + this(cond, String.valueOf(compareTo)); + } + + /** * {@inheritDoc} */ - @SuppressWarnings("incomplete-switch") @Override - public boolean matches(String val) + public boolean matches(String compareTo) { - if (condition.isNumeric()) + if (compareTo == null) { - try - { - /* - * treat a null value (no such attribute) as - * failing any numerical filter condition - */ - return val == null ? false : matches(Float.valueOf(val)); - } catch (NumberFormatException e) - { - return false; - } + return matchesNull(); } - - /* - * a null value matches a negative condition, fails a positive test - */ - if (val == null) + + boolean matched = false; + switch (patternType) { - return condition == Condition.NotContains - || condition == Condition.NotMatches - || condition == Condition.NotPresent; + case Float: + matched = matchesFloat(compareTo, floatValue); + break; + case Integer: + matched = matchesLong(compareTo); + break; + default: + matched = matchesString(compareTo); + break; } - - String upper = val.toUpperCase().trim(); + return matched; + } + + /** + * Executes a non-case-sensitive string comparison to the given value, after + * trimming it. Returns true if the test passes, false if it fails. + * + * @param compareTo + * @return + */ + boolean matchesString(String compareTo) + { boolean matched = false; + String upper = compareTo.toUpperCase().trim(); switch(condition) { case Matches: matched = upper.equals(uppercasePattern); @@ -141,38 +176,48 @@ public class Matcher implements MatcherI } /** - * Applies a numerical comparison match condition + * Performs a numerical comparison match condition test against a float value * - * @param f + * @param testee + * @param compareTo * @return */ - @SuppressWarnings("incomplete-switch") - boolean matches(float f) + boolean matchesFloat(String testee, float compareTo) { if (!condition.isNumeric()) { - return matches(String.valueOf(f)); + // failsafe, shouldn't happen + return matches(testee); + } + + float f = 0f; + try + { + f = Float.valueOf(testee); + } catch (NumberFormatException e) + { + return false; } boolean matched = false; switch (condition) { case LT: - matched = f < value; + matched = f < compareTo; break; case LE: - matched = f <= value; + matched = f <= compareTo; break; case EQ: - matched = f == value; + matched = f == compareTo; break; case NE: - matched = f != value; + matched = f != compareTo; break; case GT: - matched = f > value; + matched = f > compareTo; break; case GE: - matched = f >= value; + matched = f >= compareTo; break; default: break; @@ -188,7 +233,7 @@ public class Matcher implements MatcherI @Override public int hashCode() { - return pattern.hashCode() + condition.hashCode() + (int) value; + return pattern.hashCode() + condition.hashCode() + (int) floatValue; } /** @@ -203,7 +248,8 @@ public class Matcher implements MatcherI return false; } Matcher m = (Matcher) obj; - if (condition != m.condition || value != m.value) + if (condition != m.condition || floatValue != m.floatValue + || longValue != m.longValue) { return false; } @@ -227,12 +273,6 @@ public class Matcher implements MatcherI } @Override - public float getFloatValue() - { - return value; - } - - @Override public String toString() { StringBuilder sb = new StringBuilder(); @@ -248,4 +288,81 @@ public class Matcher implements MatcherI return sb.toString(); } + + /** + * Performs a numerical comparison match condition test against an integer + * value + * + * @param compareTo + * @return + */ + boolean matchesLong(String compareTo) + { + if (!condition.isNumeric()) + { + // failsafe, shouldn't happen + return matches(String.valueOf(compareTo)); + } + + long val = 0L; + try + { + val = Long.valueOf(compareTo); + } catch (NumberFormatException e) + { + /* + * try the presented value as a float instead + */ + return matchesFloat(compareTo, longValue); + } + + boolean matched = false; + switch (condition) { + case LT: + matched = val < longValue; + break; + case LE: + matched = val <= longValue; + break; + case EQ: + matched = val == longValue; + break; + case NE: + matched = val != longValue; + break; + case GT: + matched = val > longValue; + break; + case GE: + matched = val >= longValue; + break; + default: + break; + } + + return matched; + } + + /** + * Tests whether a null value matches the condition. The rule is that any + * numeric condition is failed, and only 'negative' string conditions are + * matched. So for example
+ * {@code null contains "damaging"}
+ * fails, but
+ * {@code null does not contain "damaging"}
+ * passes. + */ + boolean matchesNull() + { + if (condition.isNumeric()) + { + return false; + } + else + { + return condition == Condition.NotContains + || condition == Condition.NotMatches + || condition == Condition.NotPresent; + } + } } diff --git a/src/jalview/util/matcher/MatcherI.java b/src/jalview/util/matcher/MatcherI.java index ca6d44c..23e5b27 100644 --- a/src/jalview/util/matcher/MatcherI.java +++ b/src/jalview/util/matcher/MatcherI.java @@ -13,6 +13,4 @@ public interface MatcherI Condition getCondition(); String getPattern(); - - float getFloatValue(); } diff --git a/test/jalview/datamodel/features/FeatureMatcherTest.java b/test/jalview/datamodel/features/FeatureMatcherTest.java index 4bd34cb..f403a57 100644 --- a/test/jalview/datamodel/features/FeatureMatcherTest.java +++ b/test/jalview/datamodel/features/FeatureMatcherTest.java @@ -6,14 +6,17 @@ import static org.testng.Assert.assertNull; import static org.testng.Assert.assertSame; import static org.testng.Assert.assertTrue; -import jalview.datamodel.SequenceFeature; -import jalview.util.MessageManager; -import jalview.util.matcher.Condition; - import java.util.Locale; import org.testng.annotations.Test; +import jalview.datamodel.SequenceFeature; +import jalview.util.MessageManager; +import jalview.util.matcher.Condition; +import jalview.util.matcher.Matcher; +import jalview.util.matcher.MatcherI; +import junit.extensions.PA; + public class FeatureMatcherTest { @Test(groups = "Functional") @@ -222,7 +225,7 @@ public class FeatureMatcherTest FeatureMatcherI fm = FeatureMatcher.byAttribute(Condition.GE, "-2f", "AF"); assertEquals(fm.getMatcher().getCondition(), Condition.GE); - assertEquals(fm.getMatcher().getFloatValue(), -2F); + assertEquals(PA.getValue(fm.getMatcher(), "floatValue"), -2F); assertEquals(fm.getMatcher().getPattern(), "-2.0"); } @@ -233,71 +236,88 @@ public class FeatureMatcherTest assertFalse(fm.isByLabel()); assertFalse(fm.isByScore()); assertEquals(fm.getAttribute(), new String[] { "AF" }); - assertSame(Condition.LT, fm.getMatcher().getCondition()); - assertEquals(fm.getMatcher().getFloatValue(), 1.2f); - assertEquals(fm.getMatcher().getPattern(), "1.2"); + MatcherI matcher = fm.getMatcher(); + assertSame(Condition.LT, matcher.getCondition()); + assertEquals(PA.getValue(matcher, "floatValue"), 1.2f); + assertSame(PA.getValue(matcher, "patternType"), + Matcher.PatternType.Float); + assertEquals(matcher.getPattern(), "1.2"); // quotes are optional, condition is not case sensitive fm = FeatureMatcher.fromString("AF lt '1.2'"); + matcher = fm.getMatcher(); assertFalse(fm.isByLabel()); assertFalse(fm.isByScore()); assertEquals(fm.getAttribute(), new String[] { "AF" }); - assertSame(Condition.LT, fm.getMatcher().getCondition()); - assertEquals(fm.getMatcher().getFloatValue(), 1.2f); - assertEquals(fm.getMatcher().getPattern(), "1.2"); + assertSame(Condition.LT, matcher.getCondition()); + assertEquals(PA.getValue(matcher, "floatValue"), 1.2F); + assertEquals(matcher.getPattern(), "1.2"); fm = FeatureMatcher.fromString("'AF' Present"); + matcher = fm.getMatcher(); assertFalse(fm.isByLabel()); assertFalse(fm.isByScore()); assertEquals(fm.getAttribute(), new String[] { "AF" }); - assertSame(Condition.Present, fm.getMatcher().getCondition()); + assertSame(Condition.Present, matcher.getCondition()); + assertSame(PA.getValue(matcher, "patternType"), + Matcher.PatternType.String); fm = FeatureMatcher.fromString("CSQ:Consequence contains damaging"); + matcher = fm.getMatcher(); assertFalse(fm.isByLabel()); assertFalse(fm.isByScore()); assertEquals(fm.getAttribute(), new String[] { "CSQ", "Consequence" }); - assertSame(Condition.Contains, fm.getMatcher().getCondition()); - assertEquals(fm.getMatcher().getPattern(), "damaging"); + assertSame(Condition.Contains, matcher.getCondition()); + assertEquals(matcher.getPattern(), "damaging"); // keyword Label is not case sensitive fm = FeatureMatcher.fromString("LABEL Matches 'foobar'"); + matcher = fm.getMatcher(); assertTrue(fm.isByLabel()); assertFalse(fm.isByScore()); assertNull(fm.getAttribute()); - assertSame(Condition.Matches, fm.getMatcher().getCondition()); - assertEquals(fm.getMatcher().getPattern(), "foobar"); + assertSame(Condition.Matches, matcher.getCondition()); + assertEquals(matcher.getPattern(), "foobar"); fm = FeatureMatcher.fromString("'Label' matches 'foo bar'"); + matcher = fm.getMatcher(); assertTrue(fm.isByLabel()); assertFalse(fm.isByScore()); assertNull(fm.getAttribute()); - assertSame(Condition.Matches, fm.getMatcher().getCondition()); - assertEquals(fm.getMatcher().getPattern(), "foo bar"); + assertSame(Condition.Matches, matcher.getCondition()); + assertEquals(matcher.getPattern(), "foo bar"); // quotes optional on pattern fm = FeatureMatcher.fromString("'Label' matches foo bar"); + matcher = fm.getMatcher(); assertTrue(fm.isByLabel()); assertFalse(fm.isByScore()); assertNull(fm.getAttribute()); - assertSame(Condition.Matches, fm.getMatcher().getCondition()); - assertEquals(fm.getMatcher().getPattern(), "foo bar"); + assertSame(Condition.Matches, matcher.getCondition()); + assertEquals(matcher.getPattern(), "foo bar"); - fm = FeatureMatcher.fromString("Score GE 12.2"); + // integer condition + fm = FeatureMatcher.fromString("Score GE 12"); + matcher = fm.getMatcher(); assertFalse(fm.isByLabel()); assertTrue(fm.isByScore()); assertNull(fm.getAttribute()); - assertSame(Condition.GE, fm.getMatcher().getCondition()); - assertEquals(fm.getMatcher().getPattern(), "12.2"); - assertEquals(fm.getMatcher().getFloatValue(), 12.2f); + assertSame(Condition.GE, matcher.getCondition()); + assertEquals(matcher.getPattern(), "12"); + assertEquals(PA.getValue(matcher, "floatValue"), 0f); + assertEquals(PA.getValue(matcher, "longValue"), 12L); + assertSame(PA.getValue(matcher, "patternType"), + Matcher.PatternType.Integer); // keyword Score is not case sensitive fm = FeatureMatcher.fromString("'SCORE' ge '12.2'"); + matcher = fm.getMatcher(); assertFalse(fm.isByLabel()); assertTrue(fm.isByScore()); assertNull(fm.getAttribute()); - assertSame(Condition.GE, fm.getMatcher().getCondition()); - assertEquals(fm.getMatcher().getPattern(), "12.2"); - assertEquals(fm.getMatcher().getFloatValue(), 12.2f); + assertSame(Condition.GE, matcher.getCondition()); + assertEquals(matcher.getPattern(), "12.2"); + assertEquals(PA.getValue(matcher, "floatValue"), 12.2F); // invalid numeric pattern assertNull(FeatureMatcher.fromString("Score eq twelve")); diff --git a/test/jalview/gui/FeatureSettingsTest.java b/test/jalview/gui/FeatureSettingsTest.java index fd4bd4b..f09c7c7 100644 --- a/test/jalview/gui/FeatureSettingsTest.java +++ b/test/jalview/gui/FeatureSettingsTest.java @@ -4,6 +4,13 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNull; import static org.testng.Assert.assertTrue; +import java.awt.Color; +import java.io.File; +import java.io.IOException; +import java.util.HashMap; + +import org.testng.annotations.Test; + import jalview.api.FeatureColourI; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; @@ -17,13 +24,6 @@ import jalview.schemes.FeatureColourTest; import jalview.util.matcher.Condition; import jalview.viewmodel.seqfeatures.FeatureRendererModel; -import java.awt.Color; -import java.io.File; -import java.io.IOException; -import java.util.HashMap; - -import org.testng.annotations.Test; - public class FeatureSettingsTest { /** @@ -160,7 +160,7 @@ public class FeatureSettingsTest assertEquals(fr.getFeatureFilter("type2").toStableString(), "(Score LE 2.4) AND (Score GT 1.1)"); assertEquals(fr.getFeatureFilter("type3").toStableString(), - "(AF Contains X) OR (CSQ:PolyPhen NE 0.0)"); + "(AF Contains X) OR (CSQ:PolyPhen NE 0)"); } /** diff --git a/test/jalview/io/FeaturesFileTest.java b/test/jalview/io/FeaturesFileTest.java index 298ae6b..b753e94 100644 --- a/test/jalview/io/FeaturesFileTest.java +++ b/test/jalview/io/FeaturesFileTest.java @@ -27,6 +27,18 @@ import static org.testng.AssertJUnit.assertSame; import static org.testng.AssertJUnit.assertTrue; import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals; +import java.awt.Color; +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + import jalview.api.FeatureColourI; import jalview.api.FeatureRenderer; import jalview.datamodel.Alignment; @@ -47,18 +59,7 @@ import jalview.structure.StructureSelectionManager; import jalview.util.matcher.Condition; import jalview.viewmodel.seqfeatures.FeatureRendererModel; import jalview.viewmodel.seqfeatures.FeatureRendererModel.FeatureSettingsBean; - -import java.awt.Color; -import java.io.File; -import java.io.IOException; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; +import junit.extensions.PA; public class FeaturesFileTest { @@ -725,7 +726,7 @@ public class FeaturesFileTest assertTrue(matcher.isByScore()); assertSame(matcher.getMatcher().getCondition(), Condition.LT); assertEquals(matcher.getMatcher().getPattern(), "1.3"); - assertEquals(matcher.getMatcher().getFloatValue(), 1.3f); + assertEquals(PA.getValue(matcher.getMatcher(), "floatValue"), 1.3f); assertFalse(matchers.hasNext()); } diff --git a/test/jalview/project/Jalview2xmlTests.java b/test/jalview/project/Jalview2xmlTests.java index 5182ad4..77dee71 100644 --- a/test/jalview/project/Jalview2xmlTests.java +++ b/test/jalview/project/Jalview2xmlTests.java @@ -27,6 +27,21 @@ import static org.testng.Assert.assertNull; import static org.testng.Assert.assertSame; import static org.testng.Assert.assertTrue; +import java.awt.Color; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.swing.JInternalFrame; + +import org.testng.Assert; +import org.testng.AssertJUnit; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + import jalview.analysis.scoremodels.SimilarityParams; import jalview.api.AlignViewportI; import jalview.api.AlignmentViewPanel; @@ -75,21 +90,6 @@ import jalview.util.matcher.Condition; import jalview.viewmodel.AlignmentViewport; import jalview.viewmodel.seqfeatures.FeatureRendererModel; -import java.awt.Color; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.swing.JInternalFrame; - -import org.testng.Assert; -import org.testng.AssertJUnit; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; - @Test(singleThreaded = true) public class Jalview2xmlTests extends Jalview2xmlBase { @@ -1030,7 +1030,7 @@ public class Jalview2xmlTests extends Jalview2xmlBase assertEquals(fr.getFeatureFilter("type2").toStableString(), "(Score LE 2.4) AND (Score GT 1.1)"); assertEquals(fr.getFeatureFilter("type3").toStableString(), - "(AF Contains X) OR (CSQ:PolyPhen NE 0.0)"); + "(AF Contains X) OR (CSQ:PolyPhen NE 0)"); } private void addFeature(SequenceI seq, String featureType, int score) diff --git a/test/jalview/util/matcher/MatcherTest.java b/test/jalview/util/matcher/MatcherTest.java index a47fb60..d29f000 100644 --- a/test/jalview/util/matcher/MatcherTest.java +++ b/test/jalview/util/matcher/MatcherTest.java @@ -3,6 +3,7 @@ package jalview.util.matcher; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertNotEquals; +import static org.testng.Assert.assertSame; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; @@ -10,6 +11,7 @@ import java.util.Locale; import org.testng.annotations.Test; +import jalview.util.matcher.Matcher.PatternType; import junit.extensions.PA; public class MatcherTest @@ -21,22 +23,44 @@ public class MatcherTest assertEquals(m.getCondition(), Condition.Contains); assertEquals(m.getPattern(), "foo"); assertEquals(PA.getValue(m, "uppercasePattern"), "FOO"); - assertEquals(m.getFloatValue(), 0f); + assertEquals(PA.getValue(m, "floatValue"), 0f); + assertEquals(PA.getValue(m, "longValue"), 0L); + assertSame(PA.getValue(m, "patternType"), PatternType.String); m = new Matcher(Condition.GT, -2.1f); assertEquals(m.getCondition(), Condition.GT); assertEquals(m.getPattern(), "-2.1"); - assertEquals(m.getFloatValue(), -2.1f); + assertEquals(PA.getValue(m, "floatValue"), -2.1f); + assertEquals(PA.getValue(m, "longValue"), 0L); + assertSame(PA.getValue(m, "patternType"), PatternType.Float); m = new Matcher(Condition.NotContains, "-1.2f"); assertEquals(m.getCondition(), Condition.NotContains); assertEquals(m.getPattern(), "-1.2f"); - assertEquals(m.getFloatValue(), 0f); + assertEquals(PA.getValue(m, "floatValue"), 0f); + assertEquals(PA.getValue(m, "longValue"), 0L); + assertSame(PA.getValue(m, "patternType"), PatternType.String); m = new Matcher(Condition.GE, "-1.2f"); assertEquals(m.getCondition(), Condition.GE); assertEquals(m.getPattern(), "-1.2"); - assertEquals(m.getFloatValue(), -1.2f); + assertEquals(PA.getValue(m, "floatValue"), -1.2f); + assertEquals(PA.getValue(m, "longValue"), 0L); + assertSame(PA.getValue(m, "patternType"), PatternType.Float); + + m = new Matcher(Condition.GE, "113890813"); + assertEquals(m.getCondition(), Condition.GE); + assertEquals(m.getPattern(), "113890813"); + assertEquals(PA.getValue(m, "floatValue"), 0f); + assertEquals(PA.getValue(m, "longValue"), 113890813L); + assertSame(PA.getValue(m, "patternType"), PatternType.Integer); + + m = new Matcher(Condition.GE, "-987f"); + assertEquals(m.getCondition(), Condition.GE); + assertEquals(m.getPattern(), "-987.0"); + assertEquals(PA.getValue(m, "floatValue"), -987f); + assertEquals(PA.getValue(m, "longValue"), 0L); + assertSame(PA.getValue(m, "patternType"), PatternType.Float); try { @@ -53,7 +77,25 @@ public class MatcherTest fail("Expected exception"); } catch (NumberFormatException e) { - // expected + // expected - see Long.valueOf() + } + + try + { + new Matcher(Condition.LT, "123_456"); + fail("Expected exception"); + } catch (NumberFormatException e) + { + // expected - see Long.valueOf() + } + + try + { + new Matcher(Condition.LT, "123456L"); + fail("Expected exception"); + } catch (NumberFormatException e) + { + // expected - see Long.valueOf() } } @@ -82,7 +124,7 @@ public class MatcherTest /* * >= test */ - m = new Matcher(Condition.GE, 2f); + m = new Matcher(Condition.GE, "2f"); assertTrue(m.matches("2")); assertTrue(m.matches("2.1")); assertFalse(m.matches("1.9")); @@ -98,7 +140,7 @@ public class MatcherTest /* * <= test */ - m = new Matcher(Condition.LE, 2f); + m = new Matcher(Condition.LE, "2.0f"); assertTrue(m.matches("2")); assertFalse(m.matches("2.1")); assertTrue(m.matches("1.9")); @@ -112,17 +154,25 @@ public class MatcherTest assertTrue(m.matches("1.9")); } + /** + * Verifies that all numeric match conditions fail when applied to non-numeric + * or null values + */ @Test(groups = "Functional") - public void testMatches_floatNullOrInvalid() + public void testNumericMatch_nullOrInvalidValue() { for (Condition cond : Condition.values()) { if (cond.isNumeric()) { - MatcherI m = new Matcher(cond, 2f); - assertFalse(m.matches(null)); - assertFalse(m.matches("")); - assertFalse(m.matches("two")); + MatcherI m1 = new Matcher(cond, 2.1f); + MatcherI m2 = new Matcher(cond, 2345L); + assertFalse(m1.matches(null)); + assertFalse(m1.matches("")); + assertFalse(m1.matches("two")); + assertFalse(m2.matches(null)); + assertFalse(m2.matches("")); + assertFalse(m2.matches("two")); } } } @@ -166,7 +216,7 @@ public class MatcherTest */ m = new Matcher(Condition.NotMatches, "benign"); assertFalse(m.matches("benign")); - assertFalse(m.matches(" Benign ")); // trim before testing + assertFalse(m.matches(" Benign ")); // trimmed before testing assertTrue(m.matches("MOSTLY BENIGN")); assertTrue(m.matches("pathogenic")); assertTrue(m.matches(null)); @@ -188,11 +238,13 @@ public class MatcherTest assertTrue(m.matches(null)); /* - * a float with a string match condition will be treated as string + * a number with a string match condition will be treated as string */ Matcher m1 = new Matcher(Condition.Contains, "32"); - assertFalse(m1.matches(-203f)); - assertTrue(m1.matches(-4321.0f)); + assertFalse(m1.matchesFloat("-203f", 0f)); + assertTrue(m1.matchesFloat("-4321.0f", 0f)); + assertFalse(m1.matchesFloat("-203", 0f)); + assertTrue(m1.matchesFloat("-4321", 0f)); } /** @@ -202,9 +254,15 @@ public class MatcherTest public void testMatches_floatWithStringCondition() { MatcherI m = new Matcher(Condition.Contains, 1.2e-6f); + assertEquals(m.getPattern(), "1.2E-6"); + assertEquals(PA.getValue(m, "uppercasePattern"), "1.2E-6"); + assertEquals(PA.getValue(m, "floatValue"), 0f); + assertEquals(PA.getValue(m, "longValue"), 0L); + assertSame(PA.getValue(m, "patternType"), PatternType.String); assertTrue(m.matches("1.2e-6")); m = new Matcher(Condition.Contains, 0.0000001f); + assertEquals(m.getPattern(), "1.0E-7"); assertTrue(m.matches("1.0e-7")); assertTrue(m.matches("1.0E-7")); assertFalse(m.matches("0.0000001f")); @@ -218,6 +276,9 @@ public class MatcherTest MatcherI m = new Matcher(Condition.LT, 1.2e-6f); assertEquals(m.toString(), "< 1.2E-6"); + m = new Matcher(Condition.GE, "20200413"); + assertEquals(m.toString(), ">= 20200413"); + m = new Matcher(Condition.NotMatches, "ABC"); assertEquals(m.toString(), "Does not match 'ABC'"); @@ -242,7 +303,7 @@ public class MatcherTest assertFalse(m.equals(new Matcher(Condition.NotMatches, "def"))); /* - * numeric conditions + * numeric conditions - float values */ m = new Matcher(Condition.LT, -1f); assertFalse(m.equals(null)); @@ -256,6 +317,18 @@ public class MatcherTest assertFalse(m.equals(new Matcher(Condition.NE, -1f))); assertFalse(m.equals(new Matcher(Condition.LT, 1f))); assertFalse(m.equals(new Matcher(Condition.LT, -1.1f))); + + /* + * numeric conditions - integer values + */ + m = new Matcher(Condition.LT, -123456); + assertFalse(m.equals(null)); + assertFalse(m.equals("foo")); + assertTrue(m.equals(m)); + assertTrue(m.equals(new Matcher(Condition.LT, -123456))); + assertTrue(m.equals(new Matcher(Condition.LT, "-123456"))); + assertFalse(m.equals(new Matcher(Condition.LT, -123456f))); + assertFalse(m.equals(new Matcher(Condition.LT, "-123456f"))); } @Test(groups = "Functional") @@ -270,4 +343,75 @@ public class MatcherTest assertNotEquals(m1.hashCode(), m4.hashCode()); assertNotEquals(m3.hashCode(), m4.hashCode()); } + + /** + * Tests for integer comparison conditions + */ + @Test(groups = "Functional") + public void testMatches_long() + { + /* + * EQUALS test + */ + MatcherI m = new Matcher(Condition.EQ, 2); + assertTrue(m.matches("2")); + assertTrue(m.matches("+2")); + // a float value may be passed to an integer matcher + assertTrue(m.matches("2.0")); + assertTrue(m.matches("2.000000f")); + assertFalse(m.matches("2.01")); + + /* + * NOT EQUALS test + */ + m = new Matcher(Condition.NE, 123); + assertFalse(m.matches("123")); + assertFalse(m.matches("123.0")); + assertTrue(m.matches("-123")); + + /* + * >= test + */ + m = new Matcher(Condition.GE, "113890813"); + assertTrue(m.matches("113890813")); + assertTrue(m.matches("113890814")); + assertFalse(m.matches("-113890813")); + + /* + * > test + */ + m = new Matcher(Condition.GT, 113890813); + assertFalse(m.matches("113890813")); + assertTrue(m.matches("113890814")); + + /* + * <= test + */ + m = new Matcher(Condition.LE, "113890813"); + assertTrue(m.matches("113890813")); + assertFalse(m.matches("113890814")); + assertTrue(m.matches("113890812")); + + /* + * < test + */ + m = new Matcher(Condition.LT, 113890813); + assertFalse(m.matches("113890813")); + assertFalse(m.matches("113890814")); + assertTrue(m.matches("113890812")); + } + + /** + * Tests comparing a float value with an integer condition + */ + @Test(groups = "Functional") + public void testMatches_floatValueIntegerCondition() + { + MatcherI m = new Matcher(Condition.GT, 1234); + assertEquals(PA.getValue(m, "longValue"), 1234L); + assertSame(PA.getValue(m, "patternType"), PatternType.Integer); + assertTrue(m.matches("1235")); + assertTrue(m.matches("9867.345")); + assertTrue(m.matches("9867.345f")); + } } -- 1.7.10.2