JAL-2808 refactor KeyedMatcher as FeatureMatcher with byLabel, byScore, byAttribute...
[jalview.git] / test / jalview / datamodel / features / FeatureMatcherSetTest.java
1 package jalview.datamodel.features;
2
3 import static org.testng.Assert.assertEquals;
4 import static org.testng.Assert.assertFalse;
5 import static org.testng.Assert.assertSame;
6 import static org.testng.Assert.assertTrue;
7 import static org.testng.Assert.fail;
8
9 import jalview.datamodel.SequenceFeature;
10 import jalview.util.matcher.Condition;
11
12 import java.util.HashMap;
13 import java.util.Iterator;
14 import java.util.Map;
15
16 import org.testng.annotations.Test;
17
18 public class FeatureMatcherSetTest
19 {
20   @Test(groups = "Functional")
21   public void testMatches_byAttribute()
22   {
23     /*
24      * a numeric matcher - MatcherTest covers more conditions
25      */
26     FeatureMatcherI fm = FeatureMatcher.byAttribute(Condition.GE, "-2",
27             "AF");
28     FeatureMatcherSetI fms = new FeatureMatcherSet();
29     fms.and(fm);
30     SequenceFeature sf = new SequenceFeature("Cath", "desc", 11, 12, "grp");
31     assertFalse(fms.matches(sf));
32     sf.setValue("AF", "foobar");
33     assertFalse(fms.matches(sf));
34     sf.setValue("AF", "-2");
35     assertTrue(fms.matches(sf));
36     sf.setValue("AF", "-1");
37     assertTrue(fms.matches(sf));
38     sf.setValue("AF", "-3");
39     assertFalse(fms.matches(sf));
40     sf.setValue("AF", "");
41     assertFalse(fms.matches(sf));
42
43     /*
44      * a string pattern matcher
45      */
46     fm = FeatureMatcher.byAttribute(Condition.Contains, "Cat", "AF");
47     fms = new FeatureMatcherSet();
48     fms.and(fm);
49     assertFalse(fms.matches(sf));
50     sf.setValue("AF", "raining cats and dogs");
51     assertTrue(fms.matches(sf));
52   }
53
54   @Test(groups = "Functional")
55   public void testAnd()
56   {
57     // condition1: AF value contains "dog" (matches)
58     FeatureMatcherI fm1 = FeatureMatcher.byAttribute(Condition.Contains,
59             "dog", "AF");
60     // condition 2: CSQ value does not contain "how" (does not match)
61     FeatureMatcherI fm2 = FeatureMatcher.byAttribute(Condition.NotContains,
62             "how", "CSQ");
63
64     SequenceFeature sf = new SequenceFeature("Cath", "helix domain", 11, 12,
65             6.2f, "grp");
66     sf.setValue("AF", "raining cats and dogs");
67     sf.setValue("CSQ", "showers");
68
69     assertTrue(fm1.matches(sf));
70     assertFalse(fm2.matches(sf));
71
72     FeatureMatcherSetI fms = new FeatureMatcherSet();
73     assertTrue(fms.matches(sf)); // if no conditions, then 'all' pass
74     fms.and(fm1);
75     assertTrue(fms.matches(sf));
76     fms.and(fm2);
77     assertFalse(fms.matches(sf));
78
79     /*
80      * OR a failed attribute condition with a matched label condition
81      */
82     fms = new FeatureMatcherSet();
83     fms.and(fm2);
84     assertFalse(fms.matches(sf));
85     FeatureMatcher byLabelPass = FeatureMatcher.byLabel(Condition.Contains,
86             "Helix");
87     fms.or(byLabelPass);
88     assertTrue(fms.matches(sf));
89
90     /*
91      * OR a failed attribute condition with a failed score condition
92      */
93     fms = new FeatureMatcherSet();
94     fms.and(fm2);
95     assertFalse(fms.matches(sf));
96     FeatureMatcher byScoreFail = FeatureMatcher.byScore(Condition.LT,
97             "5.9");
98     fms.or(byScoreFail);
99     assertFalse(fms.matches(sf));
100
101     /*
102      * OR failed attribute and score conditions with matched label condition
103      */
104     fms = new FeatureMatcherSet();
105     fms.or(fm2).or(byScoreFail);
106     assertFalse(fms.matches(sf));
107     fms.or(byLabelPass);
108     assertTrue(fms.matches(sf));
109   }
110
111   @Test(groups = "Functional")
112   public void testToString()
113   {
114     FeatureMatcherI fm1 = FeatureMatcher.byAttribute(Condition.LT, "1.2",
115             "AF");
116     assertEquals(fm1.toString(), "AF < 1.2");
117
118     FeatureMatcher fm2 = FeatureMatcher.byAttribute(Condition.NotContains,
119             "path",
120             "CLIN_SIG");
121     assertEquals(fm2.toString(), "CLIN_SIG Does not contain 'PATH'");
122
123     /*
124      * AND them
125      */
126     FeatureMatcherSetI fms = new FeatureMatcherSet();
127     assertEquals(fms.toString(), "");
128     fms.and(fm1);
129     assertEquals(fms.toString(), "(AF < 1.2)");
130     fms.and(fm2);
131     assertEquals(fms.toString(),
132             "(AF < 1.2) AND (CLIN_SIG Does not contain 'PATH')");
133
134     /*
135      * OR them
136      */
137     fms = new FeatureMatcherSet();
138     assertEquals(fms.toString(), "");
139     fms.or(fm1);
140     assertEquals(fms.toString(), "(AF < 1.2)");
141     fms.or(fm2);
142     assertEquals(fms.toString(),
143             "(AF < 1.2) OR (CLIN_SIG Does not contain 'PATH')");
144
145     try
146     {
147       fms.and(fm1);
148       fail("Expected exception");
149     } catch (IllegalStateException e)
150     {
151       // expected
152     }
153   }
154
155   @Test(groups = "Functional")
156   public void testOr()
157   {
158     // condition1: AF value contains "dog" (matches)
159     FeatureMatcherI fm1 = FeatureMatcher.byAttribute(Condition.Contains,
160             "dog", "AF");
161     // condition 2: CSQ value does not contain "how" (does not match)
162     FeatureMatcherI fm2 = FeatureMatcher.byAttribute(Condition.NotContains,
163             "how", "CSQ");
164
165     SequenceFeature sf = new SequenceFeature("Cath", "desc", 11, 12, "grp");
166     sf.setValue("AF", "raining cats and dogs");
167     sf.setValue("CSQ", "showers");
168
169     assertTrue(fm1.matches(sf));
170     assertFalse(fm2.matches(sf));
171
172     FeatureMatcherSetI fms = new FeatureMatcherSet();
173     assertTrue(fms.matches(sf)); // if no conditions, then 'all' pass
174     fms.or(fm1);
175     assertTrue(fms.matches(sf));
176     fms.or(fm2);
177     assertTrue(fms.matches(sf)); // true or false makes true
178
179     fms = new FeatureMatcherSet();
180     fms.or(fm2);
181     assertFalse(fms.matches(sf));
182     fms.or(fm1);
183     assertTrue(fms.matches(sf)); // false or true makes true
184
185     try
186     {
187       fms.and(fm2);
188       fail("Expected exception");
189     } catch (IllegalStateException e)
190     {
191       // expected
192     }
193   }
194
195   @Test(groups = "Functional")
196   public void testIsEmpty()
197   {
198     FeatureMatcherI fm = FeatureMatcher.byAttribute(Condition.GE, "-2.0",
199             "AF");
200     FeatureMatcherSetI fms = new FeatureMatcherSet();
201     assertTrue(fms.isEmpty());
202     fms.and(fm);
203     assertFalse(fms.isEmpty());
204   }
205
206   @Test(groups = "Functional")
207   public void testGetMatchers()
208   {
209     FeatureMatcherSetI fms = new FeatureMatcherSet();
210
211     /*
212      * empty iterable:
213      */
214     Iterator<FeatureMatcherI> iterator = fms.getMatchers().iterator();
215     assertFalse(iterator.hasNext());
216
217     /*
218      * one matcher:
219      */
220     FeatureMatcherI fm1 = FeatureMatcher.byAttribute(Condition.GE, "-2",
221             "AF");
222     fms.and(fm1);
223     iterator = fms.getMatchers().iterator();
224     assertSame(fm1, iterator.next());
225     assertFalse(iterator.hasNext());
226
227     /*
228      * two matchers:
229      */
230     FeatureMatcherI fm2 = FeatureMatcher.byAttribute(Condition.LT, "8f",
231             "AF");
232     fms.and(fm2);
233     iterator = fms.getMatchers().iterator();
234     assertSame(fm1, iterator.next());
235     assertSame(fm2, iterator.next());
236     assertFalse(iterator.hasNext());
237   }
238
239   /**
240    * Tests for the 'compound attribute' key i.e. where first key's value is a map
241    * from which we take the value for the second key, e.g. CSQ : Consequence
242    */
243   @Test(groups = "Functional")
244   public void testMatches_compoundKey()
245   {
246     /*
247      * a numeric matcher - MatcherTest covers more conditions
248      */
249     FeatureMatcherI fm = FeatureMatcher.byAttribute(Condition.GE, "-2",
250             "CSQ", "Consequence");
251     SequenceFeature sf = new SequenceFeature("Cath", "desc", 2, 10, "grp");
252     FeatureMatcherSetI fms = new FeatureMatcherSet();
253     fms.and(fm);
254     assertFalse(fms.matches(sf));
255     Map<String, String> csq = new HashMap<>();
256     sf.setValue("CSQ", csq);
257     assertFalse(fms.matches(sf));
258     csq.put("Consequence", "-2");
259     assertTrue(fms.matches(sf));
260     csq.put("Consequence", "-1");
261     assertTrue(fms.matches(sf));
262     csq.put("Consequence", "-3");
263     assertFalse(fms.matches(sf));
264     csq.put("Consequence", "");
265     assertFalse(fms.matches(sf));
266     csq.put("Consequence", "junk");
267     assertFalse(fms.matches(sf));
268   
269     /*
270      * a string pattern matcher
271      */
272     fm = FeatureMatcher.byAttribute(Condition.Contains, "Cat", "CSQ",
273             "Consequence");
274     fms = new FeatureMatcherSet();
275     fms.and(fm);
276     assertFalse(fms.matches(sf));
277     csq.put("PolyPhen", "damaging");
278     assertFalse(fms.matches(sf));
279     csq.put("Consequence", "damaging");
280     assertFalse(fms.matches(sf));
281     csq.put("Consequence", "Catastrophic");
282     assertTrue(fms.matches(sf));
283   }
284 }