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.AlignViewportI;
28 import jalview.api.FinderI;
29 import jalview.bin.Cache;
30 import jalview.datamodel.Alignment;
31 import jalview.datamodel.AlignmentI;
32 import jalview.datamodel.ColumnSelection;
33 import jalview.datamodel.HiddenColumns;
34 import jalview.datamodel.SearchResultMatchI;
35 import jalview.datamodel.SearchResultsI;
36 import jalview.datamodel.Sequence;
37 import jalview.datamodel.SequenceGroup;
38 import jalview.gui.AlignFrame;
39 import jalview.gui.AlignViewport;
40 import jalview.gui.JvOptionPane;
41 import jalview.io.DataSourceType;
42 import jalview.io.FileLoader;
44 import java.util.List;
46 import org.testng.annotations.AfterMethod;
47 import org.testng.annotations.BeforeClass;
48 import org.testng.annotations.Test;
50 import junit.extensions.PA;
52 public class FinderTest
54 @BeforeClass(alwaysRun = true)
55 public void setUpJvOptionPane()
57 JvOptionPane.setInteractiveMode(false);
58 JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
61 private AlignFrame af;
63 private AlignmentI al;
65 private AlignViewportI av;
67 @BeforeClass(groups = "Functional")
71 Cache.loadProperties("test/jalview/io/testProps.jvprops");
72 Cache.setPropertyNoSave("PAD_GAPS",
73 Boolean.FALSE.toString());
75 String seqData = "seq1seq1/8-18 ABCD--EF-GHIJI\n" + "seq2 A--BCDefHI\n"
76 + "seq3 --bcdEFH\n" + "seq4 aa---aMMMMMaaa\n";
77 af = new FileLoader().LoadFileWaitTillLoaded(seqData,
78 DataSourceType.PASTE);
79 av = af.getViewport();
80 al = av.getAlignment();
83 @AfterMethod(alwaysRun = true)
84 public void tearDownAfterTest()
86 av.setSelectionGroup(null);
90 * Test for find matches of a regular expression
92 @Test(groups = "Functional")
93 public void testFind_regex()
96 * find next match only
98 Finder f = new Finder(av);
99 f.findNext("E.H", false, false); // 'E, any character, H'
100 // should match seq2 efH only
101 SearchResultsI sr = f.getSearchResults();
102 assertEquals(sr.getSize(), 1);
103 List<SearchResultMatchI> matches = sr.getResults();
104 assertSame(matches.get(0).getSequence(), al.getSequenceAt(1));
105 assertEquals(matches.get(0).getStart(), 5);
106 assertEquals(matches.get(0).getEnd(), 7);
109 f.findAll("E.H", false, false); // 'E, any character, H'
110 // should match seq2 efH and seq3 EFH
111 sr = f.getSearchResults();
112 assertEquals(sr.getSize(), 2);
113 matches = sr.getResults();
114 assertSame(matches.get(0).getSequence(), al.getSequenceAt(1));
115 assertSame(matches.get(1).getSequence(), al.getSequenceAt(2));
116 assertEquals(matches.get(0).getStart(), 5);
117 assertEquals(matches.get(0).getEnd(), 7);
118 assertEquals(matches.get(1).getStart(), 4);
119 assertEquals(matches.get(1).getEnd(), 6);
123 * Test for (undocumented) find residue by position
125 @Test(groups = "Functional")
126 public void testFind_residueNumber()
128 Finder f = new Finder(av);
131 * find first match should return seq1 residue 9
133 f.findNext("9", false, false);
134 SearchResultsI sr = f.getSearchResults();
135 assertEquals(sr.getSize(), 1);
136 List<SearchResultMatchI> matches = sr.getResults();
137 assertSame(matches.get(0).getSequence(), al.getSequenceAt(0));
138 assertEquals(matches.get(0).getStart(), 9);
139 assertEquals(matches.get(0).getEnd(), 9);
142 * find all matches should return seq1 and seq4 (others are too short)
145 f.findAll("9", false, false);
146 sr = f.getSearchResults();
147 assertEquals(sr.getSize(), 2);
148 matches = sr.getResults();
149 assertSame(matches.get(0).getSequence(), al.getSequenceAt(0));
150 assertSame(matches.get(1).getSequence(), al.getSequenceAt(3));
151 assertEquals(matches.get(0).getStart(), 9);
152 assertEquals(matches.get(0).getEnd(), 9);
153 assertEquals(matches.get(1).getStart(), 9);
154 assertEquals(matches.get(1).getEnd(), 9);
157 * parsing of search string as integer is strict
160 f.findNext(" 9", false, false);
161 assertTrue(f.getSearchResults().isEmpty());
165 * Test for find next action
167 @Test(groups = "Functional")
168 public void testFindNext()
171 * start at second sequence; colIndex of -1
172 * means sequence id / description is searched
174 Finder f = new Finder(av);
175 PA.setValue(f, "sequenceIndex", 1);
176 PA.setValue(f, "columnIndex", -1);
177 f.findNext("e", false, false); // matches id
179 assertTrue(f.getSearchResults().isEmpty());
180 assertEquals(f.getIdMatches().size(), 1);
181 assertSame(f.getIdMatches().get(0), al.getSequenceAt(1));
183 // colIndex is now 0 - for use in next find next
184 // searching A--BCDefHI
185 assertEquals(PA.getValue(f, "columnIndex"), 0);
187 PA.setValue(f, "sequenceIndex", 1);
188 PA.setValue(f, "columnIndex", 0);
189 f.findNext("e", false, false); // matches in sequence
190 assertTrue(f.getIdMatches().isEmpty());
191 assertEquals(f.getSearchResults().getSize(), 1);
192 List<SearchResultMatchI> matches = f.getSearchResults().getResults();
193 assertEquals(matches.get(0).getStart(), 5);
194 assertEquals(matches.get(0).getEnd(), 5);
195 assertSame(matches.get(0).getSequence(), al.getSequenceAt(1));
196 // still in the second sequence
197 assertEquals(PA.getValue(f, "sequenceIndex"), 1);
198 // next column position to search from is 7
199 assertEquals(PA.getValue(f, "columnIndex"), 7);
201 // find next from end of sequence - finds next sequence id
203 PA.setValue(f, "sequenceIndex", 1);
204 PA.setValue(f, "columnIndex", 7);
205 f.findNext("e", false, false);
206 assertEquals(f.getIdMatches().size(), 1);
207 assertSame(f.getIdMatches().get(0), al.getSequenceAt(2));
208 assertTrue(f.getSearchResults().isEmpty());
212 * Test for matching within sequence descriptions
214 @Test(groups = "Functional")
215 public void testFind_inDescription()
217 AlignmentI al2 = new Alignment(al);
218 al2.getSequenceAt(0).setDescription("BRAF");
219 al2.getSequenceAt(1).setDescription("braf");
221 AlignViewportI av2 = new AlignViewport(al2);
224 * find first match only
226 Finder f = new Finder(av2);
227 f.findNext("rAF", false, true);
228 assertEquals(f.getIdMatches().size(), 1);
229 assertSame(f.getIdMatches().get(0), al2.getSequenceAt(0));
230 assertTrue(f.getSearchResults().isEmpty());
236 f.findAll("rAF", false, true);
237 assertEquals(f.getIdMatches().size(), 2);
238 assertSame(f.getIdMatches().get(0), al2.getSequenceAt(0));
239 assertSame(f.getIdMatches().get(1), al2.getSequenceAt(1));
240 assertTrue(f.getSearchResults().isEmpty());
246 f.findAll("RAF", true, true);
247 assertEquals(f.getIdMatches().size(), 1);
248 assertSame(f.getIdMatches().get(0), al2.getSequenceAt(0));
249 assertTrue(f.getSearchResults().isEmpty());
252 * match sequence id, description and sequence!
254 al2.getSequenceAt(0).setDescription("the efh sequence");
255 al2.getSequenceAt(0).setName("mouseEFHkinase");
256 al2.getSequenceAt(1).setName("humanEFHkinase");
260 * sequence matches should have no duplicates
262 f.findAll("EFH", false, true);
263 assertEquals(f.getIdMatches().size(), 2);
264 assertSame(f.getIdMatches().get(0), al2.getSequenceAt(0));
265 assertSame(f.getIdMatches().get(1), al2.getSequenceAt(1));
267 assertEquals(f.getSearchResults().getSize(), 2);
268 SearchResultMatchI match = f.getSearchResults().getResults().get(0);
269 assertSame(match.getSequence(), al2.getSequenceAt(1));
270 assertEquals(match.getStart(), 5);
271 assertEquals(match.getEnd(), 7);
272 match = f.getSearchResults().getResults().get(1);
273 assertSame(match.getSequence(), al2.getSequenceAt(2));
274 assertEquals(match.getStart(), 4);
275 assertEquals(match.getEnd(), 6);
279 * Test for matching within sequence ids
281 @Test(groups = "Functional")
282 public void testFindAll_sequenceIds()
284 Finder f = new Finder(av);
287 * case insensitive; seq1 occurs twice in sequence id but
288 * only one match should be returned
290 f.findAll("SEQ1", false, false);
291 assertEquals(f.getIdMatches().size(), 1);
292 assertSame(f.getIdMatches().get(0), al.getSequenceAt(0));
293 SearchResultsI searchResults = f.getSearchResults();
294 assertTrue(searchResults.isEmpty());
300 f.findAll("SEQ1", true, false);
301 searchResults = f.getSearchResults();
302 assertTrue(searchResults.isEmpty());
305 * match both sequence id and sequence
307 AlignmentI al2 = new Alignment(al);
308 AlignViewportI av2 = new AlignViewport(al2);
309 al2.addSequence(new Sequence("aBz", "xyzabZpqrAbZ"));
311 f.findAll("ABZ", false, false);
312 assertEquals(f.getIdMatches().size(), 1);
313 assertSame(f.getIdMatches().get(0), al2.getSequenceAt(4));
314 searchResults = f.getSearchResults();
315 assertEquals(searchResults.getSize(), 2);
316 SearchResultMatchI match = searchResults.getResults().get(0);
317 assertSame(match.getSequence(), al2.getSequenceAt(4));
318 assertEquals(match.getStart(), 4);
319 assertEquals(match.getEnd(), 6);
320 match = searchResults.getResults().get(1);
321 assertSame(match.getSequence(), al2.getSequenceAt(4));
322 assertEquals(match.getStart(), 10);
323 assertEquals(match.getEnd(), 12);
327 * Test finding next match of a sequence pattern in an alignment
329 @Test(groups = "Functional")
330 public void testFind_findNext()
333 * efh should be matched in seq2 only
335 FinderI f = new Finder(av);
336 f.findNext("EfH", false, false);
337 SearchResultsI searchResults = f.getSearchResults();
338 assertEquals(searchResults.getSize(), 1);
339 SearchResultMatchI match = searchResults.getResults().get(0);
340 assertSame(match.getSequence(), al.getSequenceAt(1));
341 assertEquals(match.getStart(), 5);
342 assertEquals(match.getEnd(), 7);
345 * I should be found in seq1 (twice) and seq2 (once)
348 f.findNext("I", false, false); // find next: seq1/16
349 searchResults = f.getSearchResults();
350 assertEquals(searchResults.getSize(), 1);
351 match = searchResults.getResults().get(0);
352 assertSame(match.getSequence(), al.getSequenceAt(0));
353 assertEquals(match.getStart(), 16);
354 assertEquals(match.getEnd(), 16);
356 f.findNext("I", false, false); // find next: seq1/18
357 searchResults = f.getSearchResults();
358 assertEquals(searchResults.getSize(), 1);
359 match = searchResults.getResults().get(0);
360 assertSame(match.getSequence(), al.getSequenceAt(0));
361 assertEquals(match.getStart(), 18);
362 assertEquals(match.getEnd(), 18);
364 f.findNext("I", false, false); // find next: seq2/8
365 searchResults = f.getSearchResults();
366 assertEquals(searchResults.getSize(), 1);
367 match = searchResults.getResults().get(0);
368 assertSame(match.getSequence(), al.getSequenceAt(1));
369 assertEquals(match.getStart(), 8);
370 assertEquals(match.getEnd(), 8);
372 f.findNext("I", false, false);
373 assertTrue(f.getSearchResults().isEmpty());
376 * find should reset to start of alignment after a failed search
378 f.findNext("I", false, false); // find next: seq1/16
379 searchResults = f.getSearchResults();
380 assertEquals(searchResults.getSize(), 1);
381 match = searchResults.getResults().get(0);
382 assertSame(match.getSequence(), al.getSequenceAt(0));
383 assertEquals(match.getStart(), 16);
384 assertEquals(match.getEnd(), 16);
388 * Test for JAL-2302 to verify that sub-matches are not included in a find all
391 @Test(groups = "Functional")
392 public void testFind_maximalResultOnly()
394 Finder f = new Finder(av);
395 f.findAll("M+", false, false);
396 SearchResultsI searchResults = f.getSearchResults();
397 assertEquals(searchResults.getSize(), 1);
398 SearchResultMatchI match = searchResults.getResults().get(0);
399 assertSame(match.getSequence(), al.getSequenceAt(3));
400 assertEquals(match.getStart(), 4); // dataset sequence positions
401 assertEquals(match.getEnd(), 8); // base 1
405 * Test finding all matches of a sequence pattern in an alignment
407 @Test(groups = "Functional")
408 public void testFind_findAll()
410 Finder f = new Finder(av);
411 f.findAll("EfH", false, false);
412 SearchResultsI searchResults = f.getSearchResults();
413 assertEquals(searchResults.getSize(), 2);
414 SearchResultMatchI match = searchResults.getResults().get(0);
415 assertSame(match.getSequence(), al.getSequenceAt(1));
416 assertEquals(match.getStart(), 5);
417 assertEquals(match.getEnd(), 7);
418 match = searchResults.getResults().get(1);
419 assertSame(match.getSequence(), al.getSequenceAt(2));
420 assertEquals(match.getStart(), 4);
421 assertEquals(match.getEnd(), 6);
424 * find all I should find 2 positions in seq1, 1 in seq2
426 f.findAll("I", false, false);
427 searchResults = f.getSearchResults();
428 assertEquals(searchResults.getSize(), 3);
429 match = searchResults.getResults().get(0);
430 assertSame(match.getSequence(), al.getSequenceAt(0));
431 assertEquals(match.getStart(), 16);
432 assertEquals(match.getEnd(), 16);
433 match = searchResults.getResults().get(1);
434 assertSame(match.getSequence(), al.getSequenceAt(0));
435 assertEquals(match.getStart(), 18);
436 assertEquals(match.getEnd(), 18);
437 match = searchResults.getResults().get(2);
438 assertSame(match.getSequence(), al.getSequenceAt(1));
439 assertEquals(match.getStart(), 8);
440 assertEquals(match.getEnd(), 8);
444 * Test finding all matches, case-sensitive
446 @Test(groups = "Functional")
447 public void testFind_findAllCaseSensitive()
449 Finder f = new Finder(av);
452 * BC should match seq1/9-10 and seq2/2-3
454 f.findAll("BC", true, false);
455 SearchResultsI searchResults = f.getSearchResults();
456 assertEquals(searchResults.getSize(), 2);
457 SearchResultMatchI match = searchResults.getResults().get(0);
458 assertSame(match.getSequence(), al.getSequenceAt(0));
459 assertEquals(match.getStart(), 9);
460 assertEquals(match.getEnd(), 10);
461 match = searchResults.getResults().get(1);
462 assertSame(match.getSequence(), al.getSequenceAt(1));
463 assertEquals(match.getStart(), 2);
464 assertEquals(match.getEnd(), 3);
467 * bc should match seq3/1-2
470 f.findAll("bc", true, false);
471 searchResults = f.getSearchResults();
472 assertEquals(searchResults.getSize(), 1);
473 match = searchResults.getResults().get(0);
474 assertSame(match.getSequence(), al.getSequenceAt(2));
475 assertEquals(match.getStart(), 1);
476 assertEquals(match.getEnd(), 2);
478 f.findAll("bC", true, false);
479 assertTrue(f.getSearchResults().isEmpty());
483 * Test finding next match of a sequence pattern in a selection group
485 @Test(groups = "Functional")
486 public void testFind_inSelection()
489 * select sequences 2 and 3, columns 4-6 which contains
493 SequenceGroup sg = new SequenceGroup();
496 sg.addSequence(al.getSequenceAt(1), false);
497 sg.addSequence(al.getSequenceAt(2), false);
498 av.setSelectionGroup(sg);
500 FinderI f = new Finder(av);
501 f.findNext("b", false, false);
502 assertTrue(f.getIdMatches().isEmpty());
503 SearchResultsI searchResults = f.getSearchResults();
504 assertEquals(searchResults.getSize(), 1);
505 SearchResultMatchI match = searchResults.getResults().get(0);
506 assertSame(match.getSequence(), al.getSequenceAt(1));
507 assertEquals(match.getStart(), 2);
508 assertEquals(match.getEnd(), 2);
511 * a second Find should not return the 'b' in seq3 as outside the selection
513 f.findNext("b", false, false);
514 assertTrue(f.getSearchResults().isEmpty());
515 assertTrue(f.getIdMatches().isEmpty());
518 f.findNext("d", false, false);
519 assertTrue(f.getIdMatches().isEmpty());
520 searchResults = f.getSearchResults();
521 assertEquals(searchResults.getSize(), 1);
522 match = searchResults.getResults().get(0);
523 assertSame(match.getSequence(), al.getSequenceAt(1));
524 assertEquals(match.getStart(), 4);
525 assertEquals(match.getEnd(), 4);
526 f.findNext("d", false, false);
527 assertTrue(f.getIdMatches().isEmpty());
528 searchResults = f.getSearchResults();
529 assertEquals(searchResults.getSize(), 1);
530 match = searchResults.getResults().get(0);
531 assertSame(match.getSequence(), al.getSequenceAt(2));
532 assertEquals(match.getStart(), 3);
533 assertEquals(match.getEnd(), 3);
537 * Test finding all matches of a search pattern in a selection group
539 @Test(groups = "Functional")
540 public void testFind_findAllInSelection()
543 * select sequences 2 and 3, columns 4-6 which contains
547 SequenceGroup sg = new SequenceGroup();
550 sg.addSequence(al.getSequenceAt(1), false);
551 sg.addSequence(al.getSequenceAt(2), false);
552 av.setSelectionGroup(sg);
555 * search for 'e' should match two sequence ids and one residue
557 Finder f = new Finder(av);
558 f.findAll("e", false, false);
559 assertEquals(f.getIdMatches().size(), 2);
560 assertSame(f.getIdMatches().get(0), al.getSequenceAt(1));
561 assertSame(f.getIdMatches().get(1), al.getSequenceAt(2));
562 SearchResultsI searchResults = f.getSearchResults();
563 assertEquals(searchResults.getSize(), 1);
564 SearchResultMatchI match = searchResults.getResults().get(0);
565 assertSame(match.getSequence(), al.getSequenceAt(2));
566 assertEquals(match.getStart(), 4);
567 assertEquals(match.getEnd(), 4);
570 * search for 'Q' should match two sequence ids only
573 f.findAll("Q", false, false);
574 assertEquals(f.getIdMatches().size(), 2);
575 assertSame(f.getIdMatches().get(0), al.getSequenceAt(1));
576 assertSame(f.getIdMatches().get(1), al.getSequenceAt(2));
577 assertTrue(f.getSearchResults().isEmpty());
581 * Test finding in selection with a sequence too short to reach it
583 @Test(groups = "Functional")
584 public void testFind_findAllInSelectionWithShortSequence()
587 * select all sequences, columns 10-12
591 SequenceGroup sg = new SequenceGroup();
594 sg.addSequence(al.getSequenceAt(0), false);
595 sg.addSequence(al.getSequenceAt(1), false);
596 sg.addSequence(al.getSequenceAt(2), false);
597 sg.addSequence(al.getSequenceAt(3), false);
598 av.setSelectionGroup(sg);
601 * search for 'I' should match two sequence positions
603 Finder f = new Finder(av);
604 f.findAll("I", false, false);
605 assertTrue(f.getIdMatches().isEmpty());
606 SearchResultsI searchResults = f.getSearchResults();
607 assertEquals(searchResults.getSize(), 2);
608 SearchResultMatchI match = searchResults.getResults().get(0);
609 assertSame(match.getSequence(), al.getSequenceAt(0));
610 assertEquals(match.getStart(), 16);
611 assertEquals(match.getEnd(), 16);
612 match = searchResults.getResults().get(1);
613 assertSame(match.getSequence(), al.getSequenceAt(1));
614 assertEquals(match.getStart(), 8);
615 assertEquals(match.getEnd(), 8);
619 * Test that find does not report hidden positions
621 @Test(groups = "Functional")
622 public void testFind_withHiddenColumns()
633 * hide 2-4 (CD- -BC bcd ---)
635 HiddenColumns hc = new HiddenColumns();
636 hc.hideColumns(2, 4);
637 al.setHiddenColumns(hc);
640 * find all search for D should ignore hidden positions in seq1 and seq3,
641 * find the visible D in seq2
643 Finder f = new Finder(av);
644 f.findAll("D", false, false);
645 SearchResultsI searchResults = f.getSearchResults();
646 assertEquals(searchResults.getSize(), 1);
647 SearchResultMatchI match = searchResults.getResults().get(0);
648 assertSame(match.getSequence(), al.getSequenceAt(1));
649 assertEquals(match.getStart(), 4);
650 assertEquals(match.getEnd(), 4);
654 * find all 'aaa' should find end of seq4 only
656 hc.hideColumns(2, 5);
658 f.findAll("aaa", false, false);
659 searchResults = f.getSearchResults();
660 assertEquals(searchResults.getSize(), 1);
661 match = searchResults.getResults().get(0);
662 assertSame(match.getSequence(), al.getSequenceAt(3));
663 assertEquals(match.getStart(), 9);
664 assertEquals(match.getEnd(), 11);
667 * find all 'BE' should not match across hidden columns in seq1
669 f.findAll("BE", false, false);
670 assertTrue(f.getSearchResults().isEmpty());
673 * boundary case: hide columns at end of alignment
674 * search for H should match seq3/6 only
676 hc.revealAllHiddenColumns(new ColumnSelection());
677 hc.hideColumns(8, 13);
679 f.findNext("H", false, false);
680 searchResults = f.getSearchResults();
681 assertEquals(searchResults.getSize(), 1);
682 match = searchResults.getResults().get(0);
683 assertSame(match.getSequence(), al.getSequenceAt(2));
684 assertEquals(match.getStart(), 6);
685 assertEquals(match.getEnd(), 6);
688 @Test(groups = "Functional")
689 public void testFind_withHiddenColumnsAndSelection()
700 * hide columns 2-4 and 6-7
702 HiddenColumns hc = new HiddenColumns();
703 hc.hideColumns(2, 4);
704 hc.hideColumns(6, 7);
705 al.setHiddenColumns(hc);
710 SequenceGroup sg = new SequenceGroup();
711 sg.addSequence(al.getSequenceAt(1), false);
712 sg.addSequence(al.getSequenceAt(2), false);
715 av.setSelectionGroup(sg);
718 * find all search for A or H
719 * should match seq2/1, seq2/7, not seq3/6
721 Finder f = new Finder(av);
722 f.findAll("[AH]", false, false);
723 SearchResultsI searchResults = f.getSearchResults();
724 assertEquals(searchResults.getSize(), 2);
725 SearchResultMatchI match = searchResults.getResults().get(0);
726 assertSame(match.getSequence(), al.getSequenceAt(1));
727 assertEquals(match.getStart(), 1);
728 assertEquals(match.getEnd(), 1);
729 match = searchResults.getResults().get(1);
730 assertSame(match.getSequence(), al.getSequenceAt(1));
731 assertEquals(match.getStart(), 7);
732 assertEquals(match.getEnd(), 7);