1 package jalview.datamodel.features;
3 import static org.testng.Assert.assertEquals;
4 import static org.testng.Assert.assertFalse;
5 import static org.testng.Assert.assertNull;
6 import static org.testng.Assert.assertSame;
7 import static org.testng.Assert.assertTrue;
8 import static org.testng.Assert.fail;
10 import jalview.datamodel.SequenceFeature;
11 import jalview.util.matcher.Condition;
13 import java.util.HashMap;
14 import java.util.Iterator;
15 import java.util.Locale;
18 import org.testng.annotations.Test;
20 public class FeatureMatcherSetTest
22 @Test(groups = "Functional")
23 public void testMatches_byAttribute()
26 * a numeric matcher - MatcherTest covers more conditions
28 FeatureMatcherI fm = FeatureMatcher.byAttribute(Condition.GE, "-2",
30 FeatureMatcherSetI fms = new FeatureMatcherSet();
32 SequenceFeature sf = new SequenceFeature("Cath", "desc", 11, 12, "grp");
33 assertFalse(fms.matches(sf));
34 sf.setValue("AF", "foobar");
35 assertFalse(fms.matches(sf));
36 sf.setValue("AF", "-2");
37 assertTrue(fms.matches(sf));
38 sf.setValue("AF", "-1");
39 assertTrue(fms.matches(sf));
40 sf.setValue("AF", "-3");
41 assertFalse(fms.matches(sf));
42 sf.setValue("AF", "");
43 assertFalse(fms.matches(sf));
46 * a string pattern matcher
48 fm = FeatureMatcher.byAttribute(Condition.Contains, "Cat", "AF");
49 fms = new FeatureMatcherSet();
51 assertFalse(fms.matches(sf));
52 sf.setValue("AF", "raining cats and dogs");
53 assertTrue(fms.matches(sf));
56 @Test(groups = "Functional")
59 // condition1: AF value contains "dog" (matches)
60 FeatureMatcherI fm1 = FeatureMatcher.byAttribute(Condition.Contains,
62 // condition 2: CSQ value does not contain "how" (does not match)
63 FeatureMatcherI fm2 = FeatureMatcher.byAttribute(Condition.NotContains,
66 SequenceFeature sf = new SequenceFeature("Cath", "helix domain", 11, 12,
68 sf.setValue("AF", "raining cats and dogs");
69 sf.setValue("CSQ", "showers");
71 assertTrue(fm1.matches(sf));
72 assertFalse(fm2.matches(sf));
74 FeatureMatcherSetI fms = new FeatureMatcherSet();
75 assertTrue(fms.matches(sf)); // if no conditions, then 'all' pass
77 assertTrue(fms.matches(sf));
79 assertFalse(fms.matches(sf));
82 * OR a failed attribute condition with a matched label condition
84 fms = new FeatureMatcherSet();
86 assertFalse(fms.matches(sf));
87 FeatureMatcher byLabelPass = FeatureMatcher.byLabel(Condition.Contains,
90 assertTrue(fms.matches(sf));
93 * OR a failed attribute condition with a failed score condition
95 fms = new FeatureMatcherSet();
97 assertFalse(fms.matches(sf));
98 FeatureMatcher byScoreFail = FeatureMatcher.byScore(Condition.LT,
101 assertFalse(fms.matches(sf));
104 * OR failed attribute and score conditions with matched label condition
106 fms = new FeatureMatcherSet();
107 fms.or(fm2).or(byScoreFail);
108 assertFalse(fms.matches(sf));
110 assertTrue(fms.matches(sf));
113 @Test(groups = "Functional")
114 public void testToString()
116 Locale.setDefault(Locale.ENGLISH);
117 FeatureMatcherI fm1 = FeatureMatcher.byAttribute(Condition.LT, "1.2",
119 assertEquals(fm1.toString(), "AF < 1.2");
121 FeatureMatcher fm2 = FeatureMatcher.byAttribute(Condition.NotContains,
123 assertEquals(fm2.toString(), "CLIN_SIG does not contain 'path'");
128 FeatureMatcherSetI fms = new FeatureMatcherSet();
129 assertEquals(fms.toString(), "");
131 assertEquals(fms.toString(), "AF < 1.2");
133 assertEquals(fms.toString(),
134 "(AF < 1.2) and (CLIN_SIG does not contain 'path')");
139 fms = new FeatureMatcherSet();
140 assertEquals(fms.toString(), "");
142 assertEquals(fms.toString(), "AF < 1.2");
144 assertEquals(fms.toString(),
145 "(AF < 1.2) or (CLIN_SIG does not contain 'path')");
150 fail("Expected exception");
151 } catch (IllegalStateException e)
157 @Test(groups = "Functional")
160 // condition1: AF value contains "dog" (matches)
161 FeatureMatcherI fm1 = FeatureMatcher.byAttribute(Condition.Contains,
163 // condition 2: CSQ value does not contain "how" (does not match)
164 FeatureMatcherI fm2 = FeatureMatcher.byAttribute(Condition.NotContains,
167 SequenceFeature sf = new SequenceFeature("Cath", "desc", 11, 12, "grp");
168 sf.setValue("AF", "raining cats and dogs");
169 sf.setValue("CSQ", "showers");
171 assertTrue(fm1.matches(sf));
172 assertFalse(fm2.matches(sf));
174 FeatureMatcherSetI fms = new FeatureMatcherSet();
175 assertTrue(fms.matches(sf)); // if no conditions, then 'all' pass
177 assertTrue(fms.matches(sf));
179 assertTrue(fms.matches(sf)); // true or false makes true
181 fms = new FeatureMatcherSet();
183 assertFalse(fms.matches(sf));
185 assertTrue(fms.matches(sf)); // false or true makes true
190 fail("Expected exception");
191 } catch (IllegalStateException e)
197 @Test(groups = "Functional")
198 public void testIsEmpty()
200 FeatureMatcherI fm = FeatureMatcher.byAttribute(Condition.GE, "-2.0",
202 FeatureMatcherSetI fms = new FeatureMatcherSet();
203 assertTrue(fms.isEmpty());
205 assertFalse(fms.isEmpty());
208 @Test(groups = "Functional")
209 public void testGetMatchers()
211 FeatureMatcherSetI fms = new FeatureMatcherSet();
216 Iterator<FeatureMatcherI> iterator = fms.getMatchers().iterator();
217 assertFalse(iterator.hasNext());
222 FeatureMatcherI fm1 = FeatureMatcher.byAttribute(Condition.GE, "-2",
225 iterator = fms.getMatchers().iterator();
226 assertSame(fm1, iterator.next());
227 assertFalse(iterator.hasNext());
232 FeatureMatcherI fm2 = FeatureMatcher.byAttribute(Condition.LT, "8f",
235 iterator = fms.getMatchers().iterator();
236 assertSame(fm1, iterator.next());
237 assertSame(fm2, iterator.next());
238 assertFalse(iterator.hasNext());
242 * Tests for the 'compound attribute' key i.e. where first key's value is a map
243 * from which we take the value for the second key, e.g. CSQ : Consequence
245 @Test(groups = "Functional")
246 public void testMatches_compoundKey()
249 * a numeric matcher - MatcherTest covers more conditions
251 FeatureMatcherI fm = FeatureMatcher.byAttribute(Condition.GE, "-2",
252 "CSQ", "Consequence");
253 SequenceFeature sf = new SequenceFeature("Cath", "desc", 2, 10, "grp");
254 FeatureMatcherSetI fms = new FeatureMatcherSet();
256 assertFalse(fms.matches(sf));
257 Map<String, String> csq = new HashMap<>();
258 sf.setValue("CSQ", csq);
259 assertFalse(fms.matches(sf));
260 csq.put("Consequence", "-2");
261 assertTrue(fms.matches(sf));
262 csq.put("Consequence", "-1");
263 assertTrue(fms.matches(sf));
264 csq.put("Consequence", "-3");
265 assertFalse(fms.matches(sf));
266 csq.put("Consequence", "");
267 assertFalse(fms.matches(sf));
268 csq.put("Consequence", "junk");
269 assertFalse(fms.matches(sf));
272 * a string pattern matcher
274 fm = FeatureMatcher.byAttribute(Condition.Contains, "Cat", "CSQ",
276 fms = new FeatureMatcherSet();
278 assertFalse(fms.matches(sf));
279 csq.put("PolyPhen", "damaging");
280 assertFalse(fms.matches(sf));
281 csq.put("Consequence", "damaging");
282 assertFalse(fms.matches(sf));
283 csq.put("Consequence", "Catastrophic");
284 assertTrue(fms.matches(sf));
288 * Tests for toStableString which (unlike toString) does not i18n the
291 * @see FeatureMatcherTest#testToStableString()
293 @Test(groups = "Functional")
294 public void testToStableString()
296 FeatureMatcherI fm1 = FeatureMatcher.byAttribute(Condition.LT, "1.2",
298 assertEquals(fm1.toStableString(), "AF LT 1.2");
300 FeatureMatcher fm2 = FeatureMatcher.byAttribute(Condition.NotContains,
302 assertEquals(fm2.toStableString(), "CLIN_SIG NotContains path");
307 FeatureMatcherSetI fms = new FeatureMatcherSet();
308 assertEquals(fms.toStableString(), "");
310 // no brackets needed if a single condition
311 assertEquals(fms.toStableString(), "AF LT 1.2");
312 // brackets if more than one condition
314 assertEquals(fms.toStableString(),
315 "(AF LT 1.2) AND (CLIN_SIG NotContains path)");
320 fms = new FeatureMatcherSet();
321 assertEquals(fms.toStableString(), "");
323 assertEquals(fms.toStableString(), "AF LT 1.2");
325 assertEquals(fms.toStableString(),
326 "(AF LT 1.2) OR (CLIN_SIG NotContains path)");
329 * attribute or value including space is quoted
331 FeatureMatcher fm3 = FeatureMatcher.byAttribute(Condition.NotMatches,
332 "foo bar", "CSQ", "Poly Phen");
333 assertEquals(fm3.toStableString(),
334 "'CSQ:Poly Phen' NotMatches 'foo bar'");
336 assertEquals(fms.toStableString(),
337 "(AF LT 1.2) OR (CLIN_SIG NotContains path) OR ('CSQ:Poly Phen' NotMatches 'foo bar')");
342 fail("Expected exception");
343 } catch (IllegalStateException e)
350 * Tests for parsing a string representation of a FeatureMatcherSet
352 * @see FeatureMatcherSetTest#testToStableString()
354 @Test(groups = "Functional")
355 public void testFromString()
357 String descriptor = "AF LT 1.2";
358 FeatureMatcherSetI fms = FeatureMatcherSet.fromString(descriptor);
361 * shortcut asserts by verifying a 'roundtrip',
362 * which we trust if other tests pass :-)
364 assertEquals(fms.toStableString(), descriptor);
366 // brackets optional, quotes optional, condition case insensitive
367 fms = FeatureMatcherSet.fromString("('AF' lt '1.2')");
368 assertEquals(fms.toStableString(), descriptor);
370 descriptor = "(AF LT 1.2) AND (CLIN_SIG NotContains path)";
371 fms = FeatureMatcherSet.fromString(descriptor);
372 assertEquals(fms.toStableString(), descriptor);
374 // AND is not case-sensitive
375 fms = FeatureMatcherSet
376 .fromString("(AF LT 1.2) and (CLIN_SIG NotContains path)");
377 assertEquals(fms.toStableString(), descriptor);
379 descriptor = "(AF LT 1.2) OR (CLIN_SIG NotContains path)";
380 fms = FeatureMatcherSet.fromString(descriptor);
381 assertEquals(fms.toStableString(), descriptor);
383 // OR is not case-sensitive
384 fms = FeatureMatcherSet
385 .fromString("(AF LT 1.2) or (CLIN_SIG NotContains path)");
386 assertEquals(fms.toStableString(), descriptor);
388 // can get away without brackets on last match condition
389 fms = FeatureMatcherSet
390 .fromString("(AF LT 1.2) or CLIN_SIG NotContains path");
391 assertEquals(fms.toStableString(), descriptor);
393 descriptor = "(AF LT 1.2) OR (CLIN_SIG NotContains path) OR ('CSQ:Poly Phen' NotMatches 'foo bar')";
394 fms = FeatureMatcherSet.fromString(descriptor);
395 assertEquals(fms.toStableString(), descriptor);
397 // can't mix OR and AND
398 descriptor = "(AF LT 1.2) OR (CLIN_SIG NotContains path) AND ('CSQ:Poly Phen' NotMatches 'foo bar')";
399 assertNull(FeatureMatcherSet.fromString(descriptor));
401 // can't mix AND and OR
402 descriptor = "(AF LT 1.2) and (CLIN_SIG NotContains path) or ('CSQ:Poly Phen' NotMatches 'foo bar')";
403 assertNull(FeatureMatcherSet.fromString(descriptor));
406 assertNull(FeatureMatcherSet
407 .fromString("AF LT 1.2 or CLIN_SIG NotContains path"));
409 // invalid conjunction
410 assertNull(FeatureMatcherSet.fromString("(AF LT 1.2) but (AF GT -2)"));
412 // unbalanced quote (1)
413 assertNull(FeatureMatcherSet.fromString("('AF lt '1.2')"));
415 // unbalanced quote (2)
416 assertNull(FeatureMatcherSet.fromString("('AF' lt '1.2)"));