package jalview.datamodel.features; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertSame; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; import jalview.datamodel.SequenceFeature; import jalview.util.matcher.Condition; import java.util.HashMap; import java.util.Iterator; import java.util.Locale; import java.util.Map; import org.testng.annotations.Test; public class FeatureMatcherSetTest { @Test(groups = "Functional") public void testMatches_byAttribute() { /* * a numeric matcher - MatcherTest covers more conditions */ FeatureMatcherI fm = FeatureMatcher.byAttribute(Condition.GE, "-2", "AF"); FeatureMatcherSetI fms = new FeatureMatcherSet(); fms.and(fm); SequenceFeature sf = new SequenceFeature("Cath", "desc", 11, 12, "grp"); assertFalse(fms.matches(sf)); sf.setValue("AF", "foobar"); assertFalse(fms.matches(sf)); sf.setValue("AF", "-2"); assertTrue(fms.matches(sf)); sf.setValue("AF", "-1"); assertTrue(fms.matches(sf)); sf.setValue("AF", "-3"); assertFalse(fms.matches(sf)); sf.setValue("AF", ""); assertFalse(fms.matches(sf)); /* * a string pattern matcher */ fm = FeatureMatcher.byAttribute(Condition.Contains, "Cat", "AF"); fms = new FeatureMatcherSet(); fms.and(fm); assertFalse(fms.matches(sf)); sf.setValue("AF", "raining cats and dogs"); assertTrue(fms.matches(sf)); } @Test(groups = "Functional") public void testAnd() { // condition1: AF value contains "dog" (matches) FeatureMatcherI fm1 = FeatureMatcher.byAttribute(Condition.Contains, "dog", "AF"); // condition 2: CSQ value does not contain "how" (does not match) FeatureMatcherI fm2 = FeatureMatcher.byAttribute(Condition.NotContains, "how", "CSQ"); SequenceFeature sf = new SequenceFeature("Cath", "helix domain", 11, 12, 6.2f, "grp"); sf.setValue("AF", "raining cats and dogs"); sf.setValue("CSQ", "showers"); assertTrue(fm1.matches(sf)); assertFalse(fm2.matches(sf)); FeatureMatcherSetI fms = new FeatureMatcherSet(); assertTrue(fms.matches(sf)); // if no conditions, then 'all' pass fms.and(fm1); assertTrue(fms.matches(sf)); fms.and(fm2); assertFalse(fms.matches(sf)); /* * OR a failed attribute condition with a matched label condition */ fms = new FeatureMatcherSet(); fms.and(fm2); assertFalse(fms.matches(sf)); FeatureMatcher byLabelPass = FeatureMatcher.byLabel(Condition.Contains, "Helix"); fms.or(byLabelPass); assertTrue(fms.matches(sf)); /* * OR a failed attribute condition with a failed score condition */ fms = new FeatureMatcherSet(); fms.and(fm2); assertFalse(fms.matches(sf)); FeatureMatcher byScoreFail = FeatureMatcher.byScore(Condition.LT, "5.9"); fms.or(byScoreFail); assertFalse(fms.matches(sf)); /* * OR failed attribute and score conditions with matched label condition */ fms = new FeatureMatcherSet(); fms.or(fm2).or(byScoreFail); assertFalse(fms.matches(sf)); fms.or(byLabelPass); assertTrue(fms.matches(sf)); } @Test(groups = "Functional") public void testToString() { Locale.setDefault(Locale.ENGLISH); FeatureMatcherI fm1 = FeatureMatcher.byAttribute(Condition.LT, "1.2", "AF"); assertEquals(fm1.toString(), "AF < 1.2"); FeatureMatcher fm2 = FeatureMatcher.byAttribute(Condition.NotContains, "path", "CLIN_SIG"); assertEquals(fm2.toString(), "CLIN_SIG does not contain 'path'"); /* * AND them */ FeatureMatcherSetI fms = new FeatureMatcherSet(); assertEquals(fms.toString(), ""); fms.and(fm1); assertEquals(fms.toString(), "(AF < 1.2)"); fms.and(fm2); assertEquals(fms.toString(), "(AF < 1.2) and (CLIN_SIG does not contain 'path')"); /* * OR them */ fms = new FeatureMatcherSet(); assertEquals(fms.toString(), ""); fms.or(fm1); assertEquals(fms.toString(), "(AF < 1.2)"); fms.or(fm2); assertEquals(fms.toString(), "(AF < 1.2) or (CLIN_SIG does not contain 'path')"); try { fms.and(fm1); fail("Expected exception"); } catch (IllegalStateException e) { // expected } } @Test(groups = "Functional") public void testOr() { // condition1: AF value contains "dog" (matches) FeatureMatcherI fm1 = FeatureMatcher.byAttribute(Condition.Contains, "dog", "AF"); // condition 2: CSQ value does not contain "how" (does not match) FeatureMatcherI fm2 = FeatureMatcher.byAttribute(Condition.NotContains, "how", "CSQ"); SequenceFeature sf = new SequenceFeature("Cath", "desc", 11, 12, "grp"); sf.setValue("AF", "raining cats and dogs"); sf.setValue("CSQ", "showers"); assertTrue(fm1.matches(sf)); assertFalse(fm2.matches(sf)); FeatureMatcherSetI fms = new FeatureMatcherSet(); assertTrue(fms.matches(sf)); // if no conditions, then 'all' pass fms.or(fm1); assertTrue(fms.matches(sf)); fms.or(fm2); assertTrue(fms.matches(sf)); // true or false makes true fms = new FeatureMatcherSet(); fms.or(fm2); assertFalse(fms.matches(sf)); fms.or(fm1); assertTrue(fms.matches(sf)); // false or true makes true try { fms.and(fm2); fail("Expected exception"); } catch (IllegalStateException e) { // expected } } @Test(groups = "Functional") public void testIsEmpty() { FeatureMatcherI fm = FeatureMatcher.byAttribute(Condition.GE, "-2.0", "AF"); FeatureMatcherSetI fms = new FeatureMatcherSet(); assertTrue(fms.isEmpty()); fms.and(fm); assertFalse(fms.isEmpty()); } @Test(groups = "Functional") public void testGetMatchers() { FeatureMatcherSetI fms = new FeatureMatcherSet(); /* * empty iterable: */ Iterator iterator = fms.getMatchers().iterator(); assertFalse(iterator.hasNext()); /* * one matcher: */ FeatureMatcherI fm1 = FeatureMatcher.byAttribute(Condition.GE, "-2", "AF"); fms.and(fm1); iterator = fms.getMatchers().iterator(); assertSame(fm1, iterator.next()); assertFalse(iterator.hasNext()); /* * two matchers: */ FeatureMatcherI fm2 = FeatureMatcher.byAttribute(Condition.LT, "8f", "AF"); fms.and(fm2); iterator = fms.getMatchers().iterator(); assertSame(fm1, iterator.next()); assertSame(fm2, iterator.next()); assertFalse(iterator.hasNext()); } /** * Tests for the 'compound attribute' key i.e. where first key's value is a map * from which we take the value for the second key, e.g. CSQ : Consequence */ @Test(groups = "Functional") public void testMatches_compoundKey() { /* * a numeric matcher - MatcherTest covers more conditions */ FeatureMatcherI fm = FeatureMatcher.byAttribute(Condition.GE, "-2", "CSQ", "Consequence"); SequenceFeature sf = new SequenceFeature("Cath", "desc", 2, 10, "grp"); FeatureMatcherSetI fms = new FeatureMatcherSet(); fms.and(fm); assertFalse(fms.matches(sf)); Map csq = new HashMap<>(); sf.setValue("CSQ", csq); assertFalse(fms.matches(sf)); csq.put("Consequence", "-2"); assertTrue(fms.matches(sf)); csq.put("Consequence", "-1"); assertTrue(fms.matches(sf)); csq.put("Consequence", "-3"); assertFalse(fms.matches(sf)); csq.put("Consequence", ""); assertFalse(fms.matches(sf)); csq.put("Consequence", "junk"); assertFalse(fms.matches(sf)); /* * a string pattern matcher */ fm = FeatureMatcher.byAttribute(Condition.Contains, "Cat", "CSQ", "Consequence"); fms = new FeatureMatcherSet(); fms.and(fm); assertFalse(fms.matches(sf)); csq.put("PolyPhen", "damaging"); assertFalse(fms.matches(sf)); csq.put("Consequence", "damaging"); assertFalse(fms.matches(sf)); csq.put("Consequence", "Catastrophic"); assertTrue(fms.matches(sf)); } }