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();
109 assertFalse(fms.matches(sf));
111 assertTrue(fms.matches(sf));
114 @Test(groups = "Functional")
115 public void testToString()
117 Locale.setDefault(Locale.ENGLISH);
118 FeatureMatcherI fm1 = FeatureMatcher.byAttribute(Condition.LT, "1.2",
120 assertEquals(fm1.toString(), "AF < 1.2");
122 FeatureMatcher fm2 = FeatureMatcher.byAttribute(Condition.NotContains,
124 assertEquals(fm2.toString(), "CLIN_SIG does not contain 'path'");
129 FeatureMatcherSetI fms = new FeatureMatcherSet();
130 assertEquals(fms.toString(), "");
132 assertEquals(fms.toString(), "AF < 1.2");
134 assertEquals(fms.toString(),
135 "(AF < 1.2) and (CLIN_SIG does not contain 'path')");
140 fms = new FeatureMatcherSet();
141 assertEquals(fms.toString(), "");
143 assertEquals(fms.toString(), "AF < 1.2");
145 assertEquals(fms.toString(),
146 "(AF < 1.2) or (CLIN_SIG does not contain 'path')");
151 fail("Expected exception");
152 } catch (IllegalStateException e)
158 @Test(groups = "Functional")
161 // condition1: AF value contains "dog" (matches)
162 FeatureMatcherI fm1 = FeatureMatcher.byAttribute(Condition.Contains,
164 // condition 2: CSQ value does not contain "how" (does not match)
165 FeatureMatcherI fm2 = FeatureMatcher.byAttribute(Condition.NotContains,
168 SequenceFeature sf = new SequenceFeature("Cath", "desc", 11, 12, "grp");
169 sf.setValue("AF", "raining cats and dogs");
170 sf.setValue("CSQ", "showers");
172 assertTrue(fm1.matches(sf));
173 assertFalse(fm2.matches(sf));
175 FeatureMatcherSetI fms = new FeatureMatcherSet();
176 assertTrue(fms.matches(sf)); // if no conditions, then 'all' pass
178 assertTrue(fms.matches(sf));
180 assertTrue(fms.matches(sf)); // true or false makes true
182 fms = new FeatureMatcherSet();
184 assertFalse(fms.matches(sf));
186 assertTrue(fms.matches(sf)); // false or true makes true
191 fail("Expected exception");
192 } catch (IllegalStateException e)
198 @Test(groups = "Functional")
199 public void testIsEmpty()
201 FeatureMatcherI fm = FeatureMatcher.byAttribute(Condition.GE, "-2.0",
203 FeatureMatcherSetI fms = new FeatureMatcherSet();
204 assertTrue(fms.isEmpty());
206 assertFalse(fms.isEmpty());
209 @Test(groups = "Functional")
210 public void testGetMatchers()
212 FeatureMatcherSetI fms = new FeatureMatcherSet();
217 Iterator<FeatureMatcherI> iterator = fms.getMatchers().iterator();
218 assertFalse(iterator.hasNext());
223 FeatureMatcherI fm1 = FeatureMatcher.byAttribute(Condition.GE, "-2",
226 iterator = fms.getMatchers().iterator();
227 assertSame(fm1, iterator.next());
228 assertFalse(iterator.hasNext());
233 FeatureMatcherI fm2 = FeatureMatcher.byAttribute(Condition.LT, "8f",
236 iterator = fms.getMatchers().iterator();
237 assertSame(fm1, iterator.next());
238 assertSame(fm2, iterator.next());
239 assertFalse(iterator.hasNext());
243 * Tests for the 'compound attribute' key i.e. where first key's value is a map
244 * from which we take the value for the second key, e.g. CSQ : Consequence
246 @Test(groups = "Functional")
247 public void testMatches_compoundKey()
250 * a numeric matcher - MatcherTest covers more conditions
252 FeatureMatcherI fm = FeatureMatcher.byAttribute(Condition.GE, "-2",
253 "CSQ", "Consequence");
254 SequenceFeature sf = new SequenceFeature("Cath", "desc", 2, 10, "grp");
255 FeatureMatcherSetI fms = new FeatureMatcherSet();
257 assertFalse(fms.matches(sf));
258 Map<String, String> csq = new HashMap<>();
259 sf.setValue("CSQ", csq);
260 assertFalse(fms.matches(sf));
261 csq.put("Consequence", "-2");
262 assertTrue(fms.matches(sf));
263 csq.put("Consequence", "-1");
264 assertTrue(fms.matches(sf));
265 csq.put("Consequence", "-3");
266 assertFalse(fms.matches(sf));
267 csq.put("Consequence", "");
268 assertFalse(fms.matches(sf));
269 csq.put("Consequence", "junk");
270 assertFalse(fms.matches(sf));
273 * a string pattern matcher
275 fm = FeatureMatcher.byAttribute(Condition.Contains, "Cat", "CSQ",
277 fms = new FeatureMatcherSet();
279 assertFalse(fms.matches(sf));
280 csq.put("PolyPhen", "damaging");
281 assertFalse(fms.matches(sf));
282 csq.put("Consequence", "damaging");
283 assertFalse(fms.matches(sf));
284 csq.put("Consequence", "Catastrophic");
285 assertTrue(fms.matches(sf));
289 * Tests for toStableString which (unlike toString) does not i18n the
292 * @see FeatureMatcherTest#testToStableString()
294 @Test(groups = "Functional")
295 public void testToStableString()
297 FeatureMatcherI fm1 = FeatureMatcher.byAttribute(Condition.LT, "1.2",
299 assertEquals(fm1.toStableString(), "AF LT 1.2");
301 FeatureMatcher fm2 = FeatureMatcher.byAttribute(Condition.NotContains,
303 assertEquals(fm2.toStableString(), "CLIN_SIG NotContains path");
308 FeatureMatcherSetI fms = new FeatureMatcherSet();
309 assertEquals(fms.toStableString(), "");
311 // no brackets needed if a single condition
312 assertEquals(fms.toStableString(), "AF LT 1.2");
313 // brackets if more than one condition
315 assertEquals(fms.toStableString(),
316 "(AF LT 1.2) AND (CLIN_SIG NotContains path)");
321 fms = new FeatureMatcherSet();
322 assertEquals(fms.toStableString(), "");
324 assertEquals(fms.toStableString(), "AF LT 1.2");
326 assertEquals(fms.toStableString(),
327 "(AF LT 1.2) OR (CLIN_SIG NotContains path)");
330 * attribute or value including space is quoted
332 FeatureMatcher fm3 = FeatureMatcher.byAttribute(Condition.NotMatches,
333 "foo bar", "CSQ", "Poly Phen");
334 assertEquals(fm3.toStableString(),
335 "'CSQ:Poly Phen' NotMatches 'foo bar'");
337 assertEquals(fms.toStableString(),
338 "(AF LT 1.2) OR (CLIN_SIG NotContains path) OR ('CSQ:Poly Phen' NotMatches 'foo bar')");
343 fail("Expected exception");
344 } catch (IllegalStateException e)
351 * Tests for parsing a string representation of a FeatureMatcherSet
353 * @see FeatureMatcherSetTest#testToStableString()
355 @Test(groups = "Functional")
356 public void testFromString()
358 String descriptor = "AF LT 1.2";
359 FeatureMatcherSetI fms = FeatureMatcherSet.fromString(descriptor);
362 * shortcut asserts by verifying a 'roundtrip',
363 * which we trust if other tests pass :-)
365 assertEquals(fms.toStableString(), descriptor);
367 // brackets optional, quotes optional, condition case insensitive
368 fms = FeatureMatcherSet.fromString("('AF' lt '1.2')");
369 assertEquals(fms.toStableString(), descriptor);
371 descriptor = "(AF LT 1.2) AND (CLIN_SIG NotContains path)";
372 fms = FeatureMatcherSet.fromString(descriptor);
373 assertEquals(fms.toStableString(), descriptor);
375 // AND is not case-sensitive
376 fms = FeatureMatcherSet
377 .fromString("(AF LT 1.2) and (CLIN_SIG NotContains path)");
378 assertEquals(fms.toStableString(), descriptor);
380 descriptor = "(AF LT 1.2) OR (CLIN_SIG NotContains path)";
381 fms = FeatureMatcherSet.fromString(descriptor);
382 assertEquals(fms.toStableString(), descriptor);
384 // OR is not case-sensitive
385 fms = FeatureMatcherSet
386 .fromString("(AF LT 1.2) or (CLIN_SIG NotContains path)");
387 assertEquals(fms.toStableString(), descriptor);
389 // can get away without brackets on last match condition
390 fms = FeatureMatcherSet
391 .fromString("(AF LT 1.2) or CLIN_SIG NotContains path");
392 assertEquals(fms.toStableString(), descriptor);
394 descriptor = "(AF LT 1.2) OR (CLIN_SIG NotContains path) OR ('CSQ:Poly Phen' NotMatches 'foo bar')";
395 fms = FeatureMatcherSet.fromString(descriptor);
396 assertEquals(fms.toStableString(), descriptor);
398 // can't mix OR and AND
399 descriptor = "(AF LT 1.2) OR (CLIN_SIG NotContains path) AND ('CSQ:Poly Phen' NotMatches 'foo bar')";
400 assertNull(FeatureMatcherSet.fromString(descriptor));
402 // can't mix AND and OR
403 descriptor = "(AF LT 1.2) and (CLIN_SIG NotContains path) or ('CSQ:Poly Phen' NotMatches 'foo bar')";
404 assertNull(FeatureMatcherSet.fromString(descriptor));
407 assertNull(FeatureMatcherSet
408 .fromString("AF LT 1.2 or CLIN_SIG NotContains path"));
410 // invalid conjunction
411 assertNull(FeatureMatcherSet.fromString("(AF LT 1.2) but (AF GT -2)"));
413 // unbalanced quote (1)
414 assertNull(FeatureMatcherSet.fromString("('AF lt '1.2')"));
416 // unbalanced quote (2)
417 assertNull(FeatureMatcherSet.fromString("('AF' lt '1.2)"));