2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.datamodel.features;
23 import static org.testng.Assert.assertEquals;
24 import static org.testng.Assert.assertFalse;
25 import static org.testng.Assert.assertNull;
26 import static org.testng.Assert.assertSame;
27 import static org.testng.Assert.assertTrue;
28 import static org.testng.Assert.fail;
30 import jalview.datamodel.SequenceFeature;
31 import jalview.util.matcher.Condition;
33 import java.util.HashMap;
34 import java.util.Iterator;
35 import java.util.Locale;
38 import org.testng.annotations.Test;
40 public class FeatureMatcherSetTest
42 @Test(groups = "Functional")
43 public void testMatches_byAttribute()
46 * a numeric matcher - MatcherTest covers more conditions
48 FeatureMatcherI fm = FeatureMatcher.byAttribute(Condition.GE, "-2",
50 FeatureMatcherSetI fms = new FeatureMatcherSet();
52 SequenceFeature sf = new SequenceFeature("Cath", "desc", 11, 12, "grp");
53 assertFalse(fms.matches(sf));
54 sf.setValue("AF", "foobar");
55 assertFalse(fms.matches(sf));
56 sf.setValue("AF", "-2");
57 assertTrue(fms.matches(sf));
58 sf.setValue("AF", "-1");
59 assertTrue(fms.matches(sf));
60 sf.setValue("AF", "-3");
61 assertFalse(fms.matches(sf));
62 sf.setValue("AF", "");
63 assertFalse(fms.matches(sf));
66 * a string pattern matcher
68 fm = FeatureMatcher.byAttribute(Condition.Contains, "Cat", "AF");
69 fms = new FeatureMatcherSet();
71 assertFalse(fms.matches(sf));
72 sf.setValue("AF", "raining cats and dogs");
73 assertTrue(fms.matches(sf));
76 @Test(groups = "Functional")
79 // condition1: AF value contains "dog" (matches)
80 FeatureMatcherI fm1 = FeatureMatcher.byAttribute(Condition.Contains,
82 // condition 2: CSQ value does not contain "how" (does not match)
83 FeatureMatcherI fm2 = FeatureMatcher.byAttribute(Condition.NotContains,
86 SequenceFeature sf = new SequenceFeature("Cath", "helix domain", 11, 12,
88 sf.setValue("AF", "raining cats and dogs");
89 sf.setValue("CSQ", "showers");
91 assertTrue(fm1.matches(sf));
92 assertFalse(fm2.matches(sf));
94 FeatureMatcherSetI fms = new FeatureMatcherSet();
95 assertTrue(fms.matches(sf)); // if no conditions, then 'all' pass
97 assertTrue(fms.matches(sf));
99 assertFalse(fms.matches(sf));
102 * OR a failed attribute condition with a matched label condition
104 fms = new FeatureMatcherSet();
106 assertFalse(fms.matches(sf));
107 FeatureMatcher byLabelPass = FeatureMatcher.byLabel(Condition.Contains,
110 assertTrue(fms.matches(sf));
113 * OR a failed attribute condition with a failed score condition
115 fms = new FeatureMatcherSet();
117 assertFalse(fms.matches(sf));
118 FeatureMatcher byScoreFail = FeatureMatcher.byScore(Condition.LT,
121 assertFalse(fms.matches(sf));
124 * OR failed attribute and score conditions with matched label condition
126 fms = new FeatureMatcherSet();
129 assertFalse(fms.matches(sf));
131 assertTrue(fms.matches(sf));
134 @Test(groups = "Functional")
135 public void testToString()
137 Locale.setDefault(Locale.ENGLISH);
138 FeatureMatcherI fm1 = FeatureMatcher.byAttribute(Condition.LT, "1.2",
140 assertEquals(fm1.toString(), "AF < 1.2");
142 FeatureMatcher fm2 = FeatureMatcher.byAttribute(Condition.NotContains,
144 assertEquals(fm2.toString(), "CLIN_SIG does not contain 'path'");
149 FeatureMatcherSetI fms = new FeatureMatcherSet();
150 assertEquals(fms.toString(), "");
152 assertEquals(fms.toString(), "AF < 1.2");
154 assertEquals(fms.toString(),
155 "(AF < 1.2) and (CLIN_SIG does not contain 'path')");
160 fms = new FeatureMatcherSet();
161 assertEquals(fms.toString(), "");
163 assertEquals(fms.toString(), "AF < 1.2");
165 assertEquals(fms.toString(),
166 "(AF < 1.2) or (CLIN_SIG does not contain 'path')");
171 fail("Expected exception");
172 } catch (IllegalStateException e)
178 @Test(groups = "Functional")
181 // condition1: AF value contains "dog" (matches)
182 FeatureMatcherI fm1 = FeatureMatcher.byAttribute(Condition.Contains,
184 // condition 2: CSQ value does not contain "how" (does not match)
185 FeatureMatcherI fm2 = FeatureMatcher.byAttribute(Condition.NotContains,
188 SequenceFeature sf = new SequenceFeature("Cath", "desc", 11, 12, "grp");
189 sf.setValue("AF", "raining cats and dogs");
190 sf.setValue("CSQ", "showers");
192 assertTrue(fm1.matches(sf));
193 assertFalse(fm2.matches(sf));
195 FeatureMatcherSetI fms = new FeatureMatcherSet();
196 assertTrue(fms.matches(sf)); // if no conditions, then 'all' pass
198 assertTrue(fms.matches(sf));
200 assertTrue(fms.matches(sf)); // true or false makes true
202 fms = new FeatureMatcherSet();
204 assertFalse(fms.matches(sf));
206 assertTrue(fms.matches(sf)); // false or true makes true
211 fail("Expected exception");
212 } catch (IllegalStateException e)
218 @Test(groups = "Functional")
219 public void testIsEmpty()
221 FeatureMatcherI fm = FeatureMatcher.byAttribute(Condition.GE, "-2.0",
223 FeatureMatcherSetI fms = new FeatureMatcherSet();
224 assertTrue(fms.isEmpty());
226 assertFalse(fms.isEmpty());
229 @Test(groups = "Functional")
230 public void testGetMatchers()
232 FeatureMatcherSetI fms = new FeatureMatcherSet();
237 Iterator<FeatureMatcherI> iterator = fms.getMatchers().iterator();
238 assertFalse(iterator.hasNext());
243 FeatureMatcherI fm1 = FeatureMatcher.byAttribute(Condition.GE, "-2",
246 iterator = fms.getMatchers().iterator();
247 assertSame(fm1, iterator.next());
248 assertFalse(iterator.hasNext());
253 FeatureMatcherI fm2 = FeatureMatcher.byAttribute(Condition.LT, "8f",
256 iterator = fms.getMatchers().iterator();
257 assertSame(fm1, iterator.next());
258 assertSame(fm2, iterator.next());
259 assertFalse(iterator.hasNext());
263 * Tests for the 'compound attribute' key i.e. where first key's value is a
264 * map from which we take the value for the second key, e.g. CSQ : Consequence
266 @Test(groups = "Functional")
267 public void testMatches_compoundKey()
270 * a numeric matcher - MatcherTest covers more conditions
272 FeatureMatcherI fm = FeatureMatcher.byAttribute(Condition.GE, "-2",
273 "CSQ", "Consequence");
274 SequenceFeature sf = new SequenceFeature("Cath", "desc", 2, 10, "grp");
275 FeatureMatcherSetI fms = new FeatureMatcherSet();
277 assertFalse(fms.matches(sf));
278 Map<String, String> csq = new HashMap<>();
279 sf.setValue("CSQ", csq);
280 assertFalse(fms.matches(sf));
281 csq.put("Consequence", "-2");
282 assertTrue(fms.matches(sf));
283 csq.put("Consequence", "-1");
284 assertTrue(fms.matches(sf));
285 csq.put("Consequence", "-3");
286 assertFalse(fms.matches(sf));
287 csq.put("Consequence", "");
288 assertFalse(fms.matches(sf));
289 csq.put("Consequence", "junk");
290 assertFalse(fms.matches(sf));
293 * a string pattern matcher
295 fm = FeatureMatcher.byAttribute(Condition.Contains, "Cat", "CSQ",
297 fms = new FeatureMatcherSet();
299 assertFalse(fms.matches(sf));
300 csq.put("PolyPhen", "damaging");
301 assertFalse(fms.matches(sf));
302 csq.put("Consequence", "damaging");
303 assertFalse(fms.matches(sf));
304 csq.put("Consequence", "Catastrophic");
305 assertTrue(fms.matches(sf));
309 * Tests for toStableString which (unlike toString) does not i18n the
312 * @see FeatureMatcherTest#testToStableString()
314 @Test(groups = "Functional")
315 public void testToStableString()
317 FeatureMatcherI fm1 = FeatureMatcher.byAttribute(Condition.LT, "1.2",
319 assertEquals(fm1.toStableString(), "AF LT 1.2");
321 FeatureMatcher fm2 = FeatureMatcher.byAttribute(Condition.NotContains,
323 assertEquals(fm2.toStableString(), "CLIN_SIG NotContains path");
328 FeatureMatcherSetI fms = new FeatureMatcherSet();
329 assertEquals(fms.toStableString(), "");
331 // no brackets needed if a single condition
332 assertEquals(fms.toStableString(), "AF LT 1.2");
333 // brackets if more than one condition
335 assertEquals(fms.toStableString(),
336 "(AF LT 1.2) AND (CLIN_SIG NotContains path)");
341 fms = new FeatureMatcherSet();
342 assertEquals(fms.toStableString(), "");
344 assertEquals(fms.toStableString(), "AF LT 1.2");
346 assertEquals(fms.toStableString(),
347 "(AF LT 1.2) OR (CLIN_SIG NotContains path)");
350 * attribute or value including space is quoted
352 FeatureMatcher fm3 = FeatureMatcher.byAttribute(Condition.NotMatches,
353 "foo bar", "CSQ", "Poly Phen");
354 assertEquals(fm3.toStableString(),
355 "'CSQ:Poly Phen' NotMatches 'foo bar'");
357 assertEquals(fms.toStableString(),
358 "(AF LT 1.2) OR (CLIN_SIG NotContains path) OR ('CSQ:Poly Phen' NotMatches 'foo bar')");
363 fail("Expected exception");
364 } catch (IllegalStateException e)
371 * Tests for parsing a string representation of a FeatureMatcherSet
373 * @see FeatureMatcherSetTest#testToStableString()
375 @Test(groups = "Functional")
376 public void testFromString()
378 String descriptor = "AF LT 1.2";
379 FeatureMatcherSetI fms = FeatureMatcherSet.fromString(descriptor);
382 * shortcut asserts by verifying a 'roundtrip',
383 * which we trust if other tests pass :-)
385 assertEquals(fms.toStableString(), descriptor);
387 // brackets optional, quotes optional, condition case insensitive
388 fms = FeatureMatcherSet.fromString("('AF' lt '1.2')");
389 assertEquals(fms.toStableString(), descriptor);
391 descriptor = "(AF LT 1.2) AND (CLIN_SIG NotContains path)";
392 fms = FeatureMatcherSet.fromString(descriptor);
393 assertEquals(fms.toStableString(), descriptor);
395 // AND is not case-sensitive
396 fms = FeatureMatcherSet
397 .fromString("(AF LT 1.2) and (CLIN_SIG NotContains path)");
398 assertEquals(fms.toStableString(), descriptor);
400 descriptor = "(AF LT 1.2) OR (CLIN_SIG NotContains path)";
401 fms = FeatureMatcherSet.fromString(descriptor);
402 assertEquals(fms.toStableString(), descriptor);
404 // OR is not case-sensitive
405 fms = FeatureMatcherSet
406 .fromString("(AF LT 1.2) or (CLIN_SIG NotContains path)");
407 assertEquals(fms.toStableString(), descriptor);
409 // can get away without brackets on last match condition
410 fms = FeatureMatcherSet
411 .fromString("(AF LT 1.2) or CLIN_SIG NotContains path");
412 assertEquals(fms.toStableString(), descriptor);
414 descriptor = "(AF LT 1.2) OR (CLIN_SIG NotContains path) OR ('CSQ:Poly Phen' NotMatches 'foo bar')";
415 fms = FeatureMatcherSet.fromString(descriptor);
416 assertEquals(fms.toStableString(), descriptor);
418 // can't mix OR and AND
419 descriptor = "(AF LT 1.2) OR (CLIN_SIG NotContains path) AND ('CSQ:Poly Phen' NotMatches 'foo bar')";
420 assertNull(FeatureMatcherSet.fromString(descriptor));
422 // can't mix AND and OR
423 descriptor = "(AF LT 1.2) and (CLIN_SIG NotContains path) or ('CSQ:Poly Phen' NotMatches 'foo bar')";
424 assertNull(FeatureMatcherSet.fromString(descriptor));
427 assertNull(FeatureMatcherSet
428 .fromString("AF LT 1.2 or CLIN_SIG NotContains path"));
430 // invalid conjunction
431 assertNull(FeatureMatcherSet.fromString("(AF LT 1.2) but (AF GT -2)"));
433 // unbalanced quote (1)
434 assertNull(FeatureMatcherSet.fromString("('AF lt '1.2')"));
436 // unbalanced quote (2)
437 assertNull(FeatureMatcherSet.fromString("('AF' lt '1.2)"));