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.analysis;
23 import static org.testng.Assert.assertEquals;
24 import static org.testng.Assert.assertSame;
25 import static org.testng.Assert.assertTrue;
27 import jalview.api.FinderI;
28 import jalview.bin.Cache;
29 import jalview.datamodel.Alignment;
30 import jalview.datamodel.AlignmentI;
31 import jalview.datamodel.ColumnSelection;
32 import jalview.datamodel.HiddenColumns;
33 import jalview.datamodel.SearchResultMatchI;
34 import jalview.datamodel.SearchResultsI;
35 import jalview.datamodel.Sequence;
36 import jalview.datamodel.SequenceGroup;
37 import jalview.gui.AlignFrame;
38 import jalview.gui.JvOptionPane;
39 import jalview.io.DataSourceType;
40 import jalview.io.FileLoader;
42 import java.util.List;
44 import org.testng.annotations.BeforeClass;
45 import org.testng.annotations.Test;
47 import junit.extensions.PA;
49 public class FinderTest
51 @BeforeClass(alwaysRun = true)
52 public void setUpJvOptionPane()
54 JvOptionPane.setInteractiveMode(false);
55 JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
58 private AlignFrame af;
60 private AlignmentI al;
62 @BeforeClass(groups = "Functional")
65 Cache.loadProperties("test/jalview/io/testProps.jvprops");
66 Cache.applicationProperties.setProperty("PAD_GAPS",
67 Boolean.FALSE.toString());
69 String seqData = "seq1seq1/8-18 ABCD--EF-GHIJI\n" + "seq2 A--BCDefHI\n"
70 + "seq3 --bcdEFH\n" + "seq4 aa---aMMMMMaaa\n";
71 af = new FileLoader().LoadFileWaitTillLoaded(seqData,
72 DataSourceType.PASTE);
73 al = af.getViewport().getAlignment();
77 * Test for find matches of a regular expression
79 @Test(groups = "Functional")
80 public void testFind_regex()
83 * find next match only
85 Finder f = new Finder(al);
86 f.findNext("E.H", null, false, false); // 'E, any character, H'
87 // should match seq2 efH only
88 SearchResultsI sr = f.getSearchResults();
89 assertEquals(sr.getSize(), 1);
90 List<SearchResultMatchI> matches = sr.getResults();
91 assertSame(matches.get(0).getSequence(), al.getSequenceAt(1));
92 assertEquals(matches.get(0).getStart(), 5);
93 assertEquals(matches.get(0).getEnd(), 7);
96 f.findAll("E.H", null, false, false); // 'E, any character, H'
97 // should match seq2 efH and seq3 EFH
98 sr = f.getSearchResults();
99 assertEquals(sr.getSize(), 2);
100 matches = sr.getResults();
101 assertSame(matches.get(0).getSequence(), al.getSequenceAt(1));
102 assertSame(matches.get(1).getSequence(), al.getSequenceAt(2));
103 assertEquals(matches.get(0).getStart(), 5);
104 assertEquals(matches.get(0).getEnd(), 7);
105 assertEquals(matches.get(1).getStart(), 4);
106 assertEquals(matches.get(1).getEnd(), 6);
110 * Test for (undocumented) find residue by position
112 @Test(groups = "Functional")
113 public void testFind_residueNumber()
115 Finder f = new Finder(al);
118 * find first match should return seq1 residue 9
120 f.findNext("9", null, false, false);
121 SearchResultsI sr = f.getSearchResults();
122 assertEquals(sr.getSize(), 1);
123 List<SearchResultMatchI> matches = sr.getResults();
124 assertSame(matches.get(0).getSequence(), al.getSequenceAt(0));
125 assertEquals(matches.get(0).getStart(), 9);
126 assertEquals(matches.get(0).getEnd(), 9);
129 * find all matches should return seq1 and seq4 (others are too short)
132 f.findAll("9", null, false, false);
133 sr = f.getSearchResults();
134 assertEquals(sr.getSize(), 2);
135 matches = sr.getResults();
136 assertSame(matches.get(0).getSequence(), al.getSequenceAt(0));
137 assertSame(matches.get(1).getSequence(), al.getSequenceAt(3));
138 assertEquals(matches.get(0).getStart(), 9);
139 assertEquals(matches.get(0).getEnd(), 9);
140 assertEquals(matches.get(1).getStart(), 9);
141 assertEquals(matches.get(1).getEnd(), 9);
144 * parsing of search string as integer is strict
147 f.findNext(" 9", null, false, false);
148 assertTrue(f.getSearchResults().isEmpty());
152 * Test for find next action
154 @Test(groups = "Functional")
155 public void testFindNext()
158 * start at second sequence; colIndex of -1
159 * means sequence id / description is searched
161 Finder f = new Finder(al);
162 PA.setValue(f, "sequenceIndex", 1);
163 PA.setValue(f, "columnIndex", -1);
164 f.findNext("e", null, false, false); // matches id
166 assertTrue(f.getSearchResults().isEmpty());
167 assertEquals(f.getIdMatches().size(), 1);
168 assertSame(f.getIdMatches().get(0), al.getSequenceAt(1));
170 // colIndex is now 0 - for use in next find next
171 // searching A--BCDefHI
172 assertEquals(PA.getValue(f, "columnIndex"), 0);
174 PA.setValue(f, "sequenceIndex", 1);
175 PA.setValue(f, "columnIndex", 0);
176 f.findNext("e", null, false, false); // matches in sequence
177 assertTrue(f.getIdMatches().isEmpty());
178 assertEquals(f.getSearchResults().getSize(), 1);
179 List<SearchResultMatchI> matches = f.getSearchResults().getResults();
180 assertEquals(matches.get(0).getStart(), 5);
181 assertEquals(matches.get(0).getEnd(), 5);
182 assertSame(matches.get(0).getSequence(), al.getSequenceAt(1));
183 // still in the second sequence
184 assertEquals(PA.getValue(f, "sequenceIndex"), 1);
185 // next column position to search from is 7
186 assertEquals(PA.getValue(f, "columnIndex"), 7);
188 // find next from end of sequence - finds next sequence id
190 PA.setValue(f, "sequenceIndex", 1);
191 PA.setValue(f, "columnIndex", 7);
192 f.findNext("e", null, false, false);
193 assertEquals(f.getIdMatches().size(), 1);
194 assertSame(f.getIdMatches().get(0), al.getSequenceAt(2));
195 assertTrue(f.getSearchResults().isEmpty());
199 * Test for matching within sequence descriptions
201 @Test(groups = "Functional")
202 public void testFind_inDescription()
204 AlignmentI al2 = new Alignment(al);
205 al2.getSequenceAt(0).setDescription("BRAF");
206 al2.getSequenceAt(1).setDescription("braf");
209 * find first match only
211 Finder f = new Finder(al2);
212 f.findNext("rAF", null, false, true);
213 assertEquals(f.getIdMatches().size(), 1);
214 assertSame(f.getIdMatches().get(0), al2.getSequenceAt(0));
215 assertTrue(f.getSearchResults().isEmpty());
221 f.findAll("rAF", null, false, true);
222 assertEquals(f.getIdMatches().size(), 2);
223 assertSame(f.getIdMatches().get(0), al2.getSequenceAt(0));
224 assertSame(f.getIdMatches().get(1), al2.getSequenceAt(1));
225 assertTrue(f.getSearchResults().isEmpty());
231 f.findAll("RAF", null, true, true);
232 assertEquals(f.getIdMatches().size(), 1);
233 assertSame(f.getIdMatches().get(0), al2.getSequenceAt(0));
234 assertTrue(f.getSearchResults().isEmpty());
237 * match sequence id, description and sequence!
239 al2.getSequenceAt(0).setDescription("the efh sequence");
240 al2.getSequenceAt(0).setName("mouseEFHkinase");
241 al2.getSequenceAt(1).setName("humanEFHkinase");
245 * sequence matches should have no duplicates
247 f.findAll("EFH", null, false, true);
248 assertEquals(f.getIdMatches().size(), 2);
249 assertSame(f.getIdMatches().get(0), al2.getSequenceAt(0));
250 assertSame(f.getIdMatches().get(1), al2.getSequenceAt(1));
252 assertEquals(f.getSearchResults().getSize(), 2);
253 SearchResultMatchI match = f.getSearchResults().getResults().get(0);
254 assertSame(match.getSequence(), al2.getSequenceAt(1));
255 assertEquals(match.getStart(), 5);
256 assertEquals(match.getEnd(), 7);
257 match = f.getSearchResults().getResults().get(1);
258 assertSame(match.getSequence(), al2.getSequenceAt(2));
259 assertEquals(match.getStart(), 4);
260 assertEquals(match.getEnd(), 6);
264 * Test for matching within sequence ids
266 @Test(groups = "Functional")
267 public void testFindAll_sequenceIds()
269 Finder f = new Finder(al);
272 * case insensitive; seq1 occurs twice in sequence id but
273 * only one match should be returned
275 f.findAll("SEQ1", null, false, false);
276 assertEquals(f.getIdMatches().size(), 1);
277 assertSame(f.getIdMatches().get(0), al.getSequenceAt(0));
278 SearchResultsI searchResults = f.getSearchResults();
279 assertTrue(searchResults.isEmpty());
285 f.findAll("SEQ1", null, true, false);
286 searchResults = f.getSearchResults();
287 assertTrue(searchResults.isEmpty());
290 * match both sequence id and sequence
292 AlignmentI al2 = new Alignment(al);
293 al2.addSequence(new Sequence("aBz", "xyzabZpqrAbZ"));
295 f.findAll("ABZ", null, false, false);
296 assertEquals(f.getIdMatches().size(), 1);
297 assertSame(f.getIdMatches().get(0), al2.getSequenceAt(4));
298 searchResults = f.getSearchResults();
299 assertEquals(searchResults.getSize(), 2);
300 SearchResultMatchI match = searchResults.getResults().get(0);
301 assertSame(match.getSequence(), al2.getSequenceAt(4));
302 assertEquals(match.getStart(), 4);
303 assertEquals(match.getEnd(), 6);
304 match = searchResults.getResults().get(1);
305 assertSame(match.getSequence(), al2.getSequenceAt(4));
306 assertEquals(match.getStart(), 10);
307 assertEquals(match.getEnd(), 12);
311 * Test finding next match of a sequence pattern in an alignment
313 @Test(groups = "Functional")
314 public void testFind_findNext()
317 * efh should be matched in seq2 only
319 FinderI f = new Finder(al);
320 f.findNext("EfH", null, false, false);
321 SearchResultsI searchResults = f.getSearchResults();
322 assertEquals(searchResults.getSize(), 1);
323 SearchResultMatchI match = searchResults.getResults().get(0);
324 assertSame(match.getSequence(), al.getSequenceAt(1));
325 assertEquals(match.getStart(), 5);
326 assertEquals(match.getEnd(), 7);
329 * I should be found in seq1 (twice) and seq2 (once)
332 f.findNext("I", null, false, false); // find next: seq1/16
333 searchResults = f.getSearchResults();
334 assertEquals(searchResults.getSize(), 1);
335 match = searchResults.getResults().get(0);
336 assertSame(match.getSequence(), al.getSequenceAt(0));
337 assertEquals(match.getStart(), 16);
338 assertEquals(match.getEnd(), 16);
340 f.findNext("I", null, false, false); // find next: seq1/18
341 searchResults = f.getSearchResults();
342 assertEquals(searchResults.getSize(), 1);
343 match = searchResults.getResults().get(0);
344 assertSame(match.getSequence(), al.getSequenceAt(0));
345 assertEquals(match.getStart(), 18);
346 assertEquals(match.getEnd(), 18);
348 f.findNext("I", null, false, false); // find next: seq2/8
349 searchResults = f.getSearchResults();
350 assertEquals(searchResults.getSize(), 1);
351 match = searchResults.getResults().get(0);
352 assertSame(match.getSequence(), al.getSequenceAt(1));
353 assertEquals(match.getStart(), 8);
354 assertEquals(match.getEnd(), 8);
356 f.findNext("I", null, false, false);
357 assertTrue(f.getSearchResults().isEmpty());
360 * find should reset to start of alignment after a failed search
362 f.findNext("I", null, false, false); // find next: seq1/16
363 searchResults = f.getSearchResults();
364 assertEquals(searchResults.getSize(), 1);
365 match = searchResults.getResults().get(0);
366 assertSame(match.getSequence(), al.getSequenceAt(0));
367 assertEquals(match.getStart(), 16);
368 assertEquals(match.getEnd(), 16);
372 * Test for JAL-2302 to verify that sub-matches are not included in a find all
375 @Test(groups = "Functional")
376 public void testFind_maximalResultOnly()
378 Finder f = new Finder(al);
379 f.findAll("M+", null, false, false);
380 SearchResultsI searchResults = f.getSearchResults();
381 assertEquals(searchResults.getSize(), 1);
382 SearchResultMatchI match = searchResults.getResults().get(0);
383 assertSame(match.getSequence(), al.getSequenceAt(3));
384 assertEquals(match.getStart(), 4); // dataset sequence positions
385 assertEquals(match.getEnd(), 8); // base 1
389 * Test finding all matches of a sequence pattern in an alignment
391 @Test(groups = "Functional")
392 public void testFind_findAll()
394 Finder f = new Finder(al);
395 f.findAll("EfH", null, false, false);
396 SearchResultsI searchResults = f.getSearchResults();
397 assertEquals(searchResults.getSize(), 2);
398 SearchResultMatchI match = searchResults.getResults().get(0);
399 assertSame(match.getSequence(), al.getSequenceAt(1));
400 assertEquals(match.getStart(), 5);
401 assertEquals(match.getEnd(), 7);
402 match = searchResults.getResults().get(1);
403 assertSame(match.getSequence(), al.getSequenceAt(2));
404 assertEquals(match.getStart(), 4);
405 assertEquals(match.getEnd(), 6);
408 * find all I should find 2 positions in seq1, 1 in seq2
410 f.findAll("I", null, false, false);
411 searchResults = f.getSearchResults();
412 assertEquals(searchResults.getSize(), 3);
413 match = searchResults.getResults().get(0);
414 assertSame(match.getSequence(), al.getSequenceAt(0));
415 assertEquals(match.getStart(), 16);
416 assertEquals(match.getEnd(), 16);
417 match = searchResults.getResults().get(1);
418 assertSame(match.getSequence(), al.getSequenceAt(0));
419 assertEquals(match.getStart(), 18);
420 assertEquals(match.getEnd(), 18);
421 match = searchResults.getResults().get(2);
422 assertSame(match.getSequence(), al.getSequenceAt(1));
423 assertEquals(match.getStart(), 8);
424 assertEquals(match.getEnd(), 8);
428 * Test finding all matches, case-sensitive
430 @Test(groups = "Functional")
431 public void testFind_findAllCaseSensitive()
433 Finder f = new Finder(al);
436 * BC should match seq1/9-10 and seq2/2-3
438 f.findAll("BC", null, true, false);
439 SearchResultsI searchResults = f.getSearchResults();
440 assertEquals(searchResults.getSize(), 2);
441 SearchResultMatchI match = searchResults.getResults().get(0);
442 assertSame(match.getSequence(), al.getSequenceAt(0));
443 assertEquals(match.getStart(), 9);
444 assertEquals(match.getEnd(), 10);
445 match = searchResults.getResults().get(1);
446 assertSame(match.getSequence(), al.getSequenceAt(1));
447 assertEquals(match.getStart(), 2);
448 assertEquals(match.getEnd(), 3);
451 * bc should match seq3/1-2
454 f.findAll("bc", null, true, false);
455 searchResults = f.getSearchResults();
456 assertEquals(searchResults.getSize(), 1);
457 match = searchResults.getResults().get(0);
458 assertSame(match.getSequence(), al.getSequenceAt(2));
459 assertEquals(match.getStart(), 1);
460 assertEquals(match.getEnd(), 2);
462 f.findAll("bC", null, true, false);
463 assertTrue(f.getSearchResults().isEmpty());
467 * Test finding next match of a sequence pattern in a selection group
469 @Test(groups = "Functional")
470 public void testFind_inSelection()
473 * select sequences 2 and 3, columns 4-6 which contains
477 SequenceGroup sg = new SequenceGroup();
480 sg.addSequence(al.getSequenceAt(1), false);
481 sg.addSequence(al.getSequenceAt(2), false);
483 FinderI f = new Finder(al);
484 f.findNext("b", sg, false, false);
485 assertTrue(f.getIdMatches().isEmpty());
486 SearchResultsI searchResults = f.getSearchResults();
487 assertEquals(searchResults.getSize(), 1);
488 SearchResultMatchI match = searchResults.getResults().get(0);
489 assertSame(match.getSequence(), al.getSequenceAt(1));
490 assertEquals(match.getStart(), 2);
491 assertEquals(match.getEnd(), 2);
494 * a second Find should not return the 'b' in seq3 as outside the selection
496 f.findNext("b", sg, false, false);
497 assertTrue(f.getSearchResults().isEmpty());
498 assertTrue(f.getIdMatches().isEmpty());
501 f.findNext("d", sg, false, false);
502 assertTrue(f.getIdMatches().isEmpty());
503 searchResults = f.getSearchResults();
504 assertEquals(searchResults.getSize(), 1);
505 match = searchResults.getResults().get(0);
506 assertSame(match.getSequence(), al.getSequenceAt(1));
507 assertEquals(match.getStart(), 4);
508 assertEquals(match.getEnd(), 4);
509 f.findNext("d", sg, false, false);
510 assertTrue(f.getIdMatches().isEmpty());
511 searchResults = f.getSearchResults();
512 assertEquals(searchResults.getSize(), 1);
513 match = searchResults.getResults().get(0);
514 assertSame(match.getSequence(), al.getSequenceAt(2));
515 assertEquals(match.getStart(), 3);
516 assertEquals(match.getEnd(), 3);
520 * Test finding all matches of a search pattern in a selection group
522 @Test(groups = "Functional")
523 public void testFind_findAllInSelection()
526 * select sequences 2 and 3, columns 4-6 which contains
530 SequenceGroup sg = new SequenceGroup();
533 sg.addSequence(al.getSequenceAt(1), false);
534 sg.addSequence(al.getSequenceAt(2), false);
537 * search for 'e' should match two sequence ids and one residue
539 Finder f = new Finder(al);
540 f.findAll("e", sg, false, false);
541 assertEquals(f.getIdMatches().size(), 2);
542 assertSame(f.getIdMatches().get(0), al.getSequenceAt(1));
543 assertSame(f.getIdMatches().get(1), al.getSequenceAt(2));
544 SearchResultsI searchResults = f.getSearchResults();
545 assertEquals(searchResults.getSize(), 1);
546 SearchResultMatchI match = searchResults.getResults().get(0);
547 assertSame(match.getSequence(), al.getSequenceAt(2));
548 assertEquals(match.getStart(), 4);
549 assertEquals(match.getEnd(), 4);
552 * search for 'Q' should match two sequence ids only
555 f.findAll("Q", sg, false, false);
556 assertEquals(f.getIdMatches().size(), 2);
557 assertSame(f.getIdMatches().get(0), al.getSequenceAt(1));
558 assertSame(f.getIdMatches().get(1), al.getSequenceAt(2));
559 assertTrue(f.getSearchResults().isEmpty());
563 * Test finding in selection with a sequence too short to reach it
565 @Test(groups = "Functional")
566 public void testFind_findAllInSelectionWithShortSequence()
569 * select all sequences, columns 10-12
573 SequenceGroup sg = new SequenceGroup();
576 sg.addSequence(al.getSequenceAt(0), false);
577 sg.addSequence(al.getSequenceAt(1), false);
578 sg.addSequence(al.getSequenceAt(2), false);
579 sg.addSequence(al.getSequenceAt(3), false);
582 * search for 'I' should match two sequence positions
584 Finder f = new Finder(al);
585 f.findAll("I", sg, false, false);
586 assertTrue(f.getIdMatches().isEmpty());
587 SearchResultsI searchResults = f.getSearchResults();
588 assertEquals(searchResults.getSize(), 2);
589 SearchResultMatchI match = searchResults.getResults().get(0);
590 assertSame(match.getSequence(), al.getSequenceAt(0));
591 assertEquals(match.getStart(), 16);
592 assertEquals(match.getEnd(), 16);
593 match = searchResults.getResults().get(1);
594 assertSame(match.getSequence(), al.getSequenceAt(1));
595 assertEquals(match.getStart(), 8);
596 assertEquals(match.getEnd(), 8);
600 * Test that find does not report hidden positions
602 @Test(groups = "Functional")
603 public void testFind_withHiddenColumns()
614 * hide 2-4 (CD- -BC bcd ---)
616 HiddenColumns hc = new HiddenColumns();
617 hc.hideColumns(2, 4);
618 al.setHiddenColumns(hc);
621 * find all search for D should ignore hidden positions in seq1 and seq3,
622 * find the visible D in seq2
624 Finder f = new Finder(al);
625 f.findAll("D", null, false, false);
626 SearchResultsI searchResults = f.getSearchResults();
627 assertEquals(searchResults.getSize(), 1);
628 SearchResultMatchI match = searchResults.getResults().get(0);
629 assertSame(match.getSequence(), al.getSequenceAt(1));
630 assertEquals(match.getStart(), 4);
631 assertEquals(match.getEnd(), 4);
635 * find all 'aaa' should find end of seq4 only
637 hc.hideColumns(2, 5);
639 f.findAll("aaa", null, false, false);
640 searchResults = f.getSearchResults();
641 assertEquals(searchResults.getSize(), 1);
642 match = searchResults.getResults().get(0);
643 assertSame(match.getSequence(), al.getSequenceAt(3));
644 assertEquals(match.getStart(), 9);
645 assertEquals(match.getEnd(), 11);
648 * find all 'BE' should not match across hidden columns in seq1
650 f.findAll("BE", null, false, false);
651 assertTrue(f.getSearchResults().isEmpty());
654 * boundary case: hide columns at end of alignment
655 * search for H should match seq3/6 only
657 hc.revealAllHiddenColumns(new ColumnSelection());
658 hc.hideColumns(8, 13);
660 f.findNext("H", null, false, false);
661 searchResults = f.getSearchResults();
662 assertEquals(searchResults.getSize(), 1);
663 match = searchResults.getResults().get(0);
664 assertSame(match.getSequence(), al.getSequenceAt(2));
665 assertEquals(match.getStart(), 6);
666 assertEquals(match.getEnd(), 6);
669 @Test(groups = "Functional")
670 public void testFind_withHiddenColumnsAndSelection()
681 * hide columns 2-4 and 6-7
683 HiddenColumns hc = new HiddenColumns();
684 hc.hideColumns(2, 4);
685 hc.hideColumns(6, 7);
686 al.setHiddenColumns(hc);
691 SequenceGroup sg = new SequenceGroup();
692 sg.addSequence(al.getSequenceAt(1), false);
693 sg.addSequence(al.getSequenceAt(2), false);
698 * find all search for A or H
699 * should match seq2/1, seq2/7, not seq3/6
701 Finder f = new Finder(al);
702 f.findAll("[AH]", sg, false, false);
703 SearchResultsI searchResults = f.getSearchResults();
704 assertEquals(searchResults.getSize(), 2);
705 SearchResultMatchI match = searchResults.getResults().get(0);
706 assertSame(match.getSequence(), al.getSequenceAt(1));
707 assertEquals(match.getStart(), 1);
708 assertEquals(match.getEnd(), 1);
709 match = searchResults.getResults().get(1);
710 assertSame(match.getSequence(), al.getSequenceAt(1));
711 assertEquals(match.getStart(), 7);
712 assertEquals(match.getEnd(), 7);