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")
70 Cache.loadProperties("test/jalview/io/testProps.jvprops");
71 Cache.applicationProperties.setProperty("PAD_GAPS",
72 Boolean.FALSE.toString());
74 String seqData = "seq1seq1/8-18 ABCD--EF-GHIJI\n" + "seq2 A--BCDefHI\n"
75 + "seq3 --bcdEFH\n" + "seq4 aa---aMMMMMaaa\n";
76 af = new FileLoader().LoadFileWaitTillLoaded(seqData,
77 DataSourceType.PASTE);
78 av = af.getViewport();
79 al = av.getAlignment();
82 @AfterMethod(alwaysRun = true)
83 public void tearDownAfterTest()
85 av.setSelectionGroup(null);
89 * Test for find matches of a regular expression
91 @Test(groups = "Functional")
92 public void testFind_regex()
95 * find next match only
97 Finder f = new Finder(av);
98 f.findNext("E.H", false, false); // 'E, any character, H'
99 // should match seq2 efH only
100 SearchResultsI sr = f.getSearchResults();
101 assertEquals(sr.getSize(), 1);
102 List<SearchResultMatchI> matches = sr.getResults();
103 assertSame(matches.get(0).getSequence(), al.getSequenceAt(1));
104 assertEquals(matches.get(0).getStart(), 5);
105 assertEquals(matches.get(0).getEnd(), 7);
108 f.findAll("E.H", false, false); // 'E, any character, H'
109 // should match seq2 efH and seq3 EFH
110 sr = f.getSearchResults();
111 assertEquals(sr.getSize(), 2);
112 matches = sr.getResults();
113 assertSame(matches.get(0).getSequence(), al.getSequenceAt(1));
114 assertSame(matches.get(1).getSequence(), al.getSequenceAt(2));
115 assertEquals(matches.get(0).getStart(), 5);
116 assertEquals(matches.get(0).getEnd(), 7);
117 assertEquals(matches.get(1).getStart(), 4);
118 assertEquals(matches.get(1).getEnd(), 6);
122 * Test for (undocumented) find residue by position
124 @Test(groups = "Functional")
125 public void testFind_residueNumber()
127 Finder f = new Finder(av);
130 * find first match should return seq1 residue 9
132 f.findNext("9", false, false);
133 SearchResultsI sr = f.getSearchResults();
134 assertEquals(sr.getSize(), 1);
135 List<SearchResultMatchI> matches = sr.getResults();
136 assertSame(matches.get(0).getSequence(), al.getSequenceAt(0));
137 assertEquals(matches.get(0).getStart(), 9);
138 assertEquals(matches.get(0).getEnd(), 9);
141 * find all matches should return seq1 and seq4 (others are too short)
144 f.findAll("9", false, false);
145 sr = f.getSearchResults();
146 assertEquals(sr.getSize(), 2);
147 matches = sr.getResults();
148 assertSame(matches.get(0).getSequence(), al.getSequenceAt(0));
149 assertSame(matches.get(1).getSequence(), al.getSequenceAt(3));
150 assertEquals(matches.get(0).getStart(), 9);
151 assertEquals(matches.get(0).getEnd(), 9);
152 assertEquals(matches.get(1).getStart(), 9);
153 assertEquals(matches.get(1).getEnd(), 9);
156 * parsing of search string as integer is strict
159 f.findNext(" 9", false, false);
160 assertTrue(f.getSearchResults().isEmpty());
164 * Test for find next action
166 @Test(groups = "Functional")
167 public void testFindNext()
170 * start at second sequence; colIndex of -1
171 * means sequence id / description is searched
173 Finder f = new Finder(av);
174 PA.setValue(f, "sequenceIndex", 1);
175 PA.setValue(f, "columnIndex", -1);
176 f.findNext("e", false, false); // matches id
178 assertTrue(f.getSearchResults().isEmpty());
179 assertEquals(f.getIdMatches().size(), 1);
180 assertSame(f.getIdMatches().get(0), al.getSequenceAt(1));
182 // colIndex is now 0 - for use in next find next
183 // searching A--BCDefHI
184 assertEquals(PA.getValue(f, "columnIndex"), 0);
186 PA.setValue(f, "sequenceIndex", 1);
187 PA.setValue(f, "columnIndex", 0);
188 f.findNext("e", false, false); // matches in sequence
189 assertTrue(f.getIdMatches().isEmpty());
190 assertEquals(f.getSearchResults().getSize(), 1);
191 List<SearchResultMatchI> matches = f.getSearchResults().getResults();
192 assertEquals(matches.get(0).getStart(), 5);
193 assertEquals(matches.get(0).getEnd(), 5);
194 assertSame(matches.get(0).getSequence(), al.getSequenceAt(1));
195 // still in the second sequence
196 assertEquals(PA.getValue(f, "sequenceIndex"), 1);
197 // next column position to search from is 7
198 assertEquals(PA.getValue(f, "columnIndex"), 7);
200 // find next from end of sequence - finds next sequence id
202 PA.setValue(f, "sequenceIndex", 1);
203 PA.setValue(f, "columnIndex", 7);
204 f.findNext("e", false, false);
205 assertEquals(f.getIdMatches().size(), 1);
206 assertSame(f.getIdMatches().get(0), al.getSequenceAt(2));
207 assertTrue(f.getSearchResults().isEmpty());
211 * Test for matching within sequence descriptions
213 @Test(groups = "Functional")
214 public void testFind_inDescription()
216 AlignmentI al2 = new Alignment(al);
217 al2.getSequenceAt(0).setDescription("BRAF");
218 al2.getSequenceAt(1).setDescription("braf");
220 AlignViewportI av2 = new AlignViewport(al2);
223 * find first match only
225 Finder f = new Finder(av2);
226 f.findNext("rAF", false, true);
227 assertEquals(f.getIdMatches().size(), 1);
228 assertSame(f.getIdMatches().get(0), al2.getSequenceAt(0));
229 assertTrue(f.getSearchResults().isEmpty());
235 f.findAll("rAF", false, true);
236 assertEquals(f.getIdMatches().size(), 2);
237 assertSame(f.getIdMatches().get(0), al2.getSequenceAt(0));
238 assertSame(f.getIdMatches().get(1), al2.getSequenceAt(1));
239 assertTrue(f.getSearchResults().isEmpty());
245 f.findAll("RAF", true, true);
246 assertEquals(f.getIdMatches().size(), 1);
247 assertSame(f.getIdMatches().get(0), al2.getSequenceAt(0));
248 assertTrue(f.getSearchResults().isEmpty());
251 * match sequence id, description and sequence!
253 al2.getSequenceAt(0).setDescription("the efh sequence");
254 al2.getSequenceAt(0).setName("mouseEFHkinase");
255 al2.getSequenceAt(1).setName("humanEFHkinase");
259 * sequence matches should have no duplicates
261 f.findAll("EFH", false, true);
262 assertEquals(f.getIdMatches().size(), 2);
263 assertSame(f.getIdMatches().get(0), al2.getSequenceAt(0));
264 assertSame(f.getIdMatches().get(1), al2.getSequenceAt(1));
266 assertEquals(f.getSearchResults().getSize(), 2);
267 SearchResultMatchI match = f.getSearchResults().getResults().get(0);
268 assertSame(match.getSequence(), al2.getSequenceAt(1));
269 assertEquals(match.getStart(), 5);
270 assertEquals(match.getEnd(), 7);
271 match = f.getSearchResults().getResults().get(1);
272 assertSame(match.getSequence(), al2.getSequenceAt(2));
273 assertEquals(match.getStart(), 4);
274 assertEquals(match.getEnd(), 6);
278 * Test for matching within sequence ids
280 @Test(groups = "Functional")
281 public void testFindAll_sequenceIds()
283 Finder f = new Finder(av);
286 * case insensitive; seq1 occurs twice in sequence id but
287 * only one match should be returned
289 f.findAll("SEQ1", false, false);
290 assertEquals(f.getIdMatches().size(), 1);
291 assertSame(f.getIdMatches().get(0), al.getSequenceAt(0));
292 SearchResultsI searchResults = f.getSearchResults();
293 assertTrue(searchResults.isEmpty());
299 f.findAll("SEQ1", true, false);
300 searchResults = f.getSearchResults();
301 assertTrue(searchResults.isEmpty());
304 * match both sequence id and sequence
306 AlignmentI al2 = new Alignment(al);
307 AlignViewportI av2 = new AlignViewport(al2);
308 al2.addSequence(new Sequence("aBz", "xyzabZpqrAbZ"));
310 f.findAll("ABZ", false, false);
311 assertEquals(f.getIdMatches().size(), 1);
312 assertSame(f.getIdMatches().get(0), al2.getSequenceAt(4));
313 searchResults = f.getSearchResults();
314 assertEquals(searchResults.getSize(), 2);
315 SearchResultMatchI match = searchResults.getResults().get(0);
316 assertSame(match.getSequence(), al2.getSequenceAt(4));
317 assertEquals(match.getStart(), 4);
318 assertEquals(match.getEnd(), 6);
319 match = searchResults.getResults().get(1);
320 assertSame(match.getSequence(), al2.getSequenceAt(4));
321 assertEquals(match.getStart(), 10);
322 assertEquals(match.getEnd(), 12);
326 * Test finding next match of a sequence pattern in an alignment
328 @Test(groups = "Functional")
329 public void testFind_findNext()
332 * efh should be matched in seq2 only
334 FinderI f = new Finder(av);
335 f.findNext("EfH", false, false);
336 SearchResultsI searchResults = f.getSearchResults();
337 assertEquals(searchResults.getSize(), 1);
338 SearchResultMatchI match = searchResults.getResults().get(0);
339 assertSame(match.getSequence(), al.getSequenceAt(1));
340 assertEquals(match.getStart(), 5);
341 assertEquals(match.getEnd(), 7);
344 * I should be found in seq1 (twice) and seq2 (once)
347 f.findNext("I", false, false); // find next: seq1/16
348 searchResults = f.getSearchResults();
349 assertEquals(searchResults.getSize(), 1);
350 match = searchResults.getResults().get(0);
351 assertSame(match.getSequence(), al.getSequenceAt(0));
352 assertEquals(match.getStart(), 16);
353 assertEquals(match.getEnd(), 16);
355 f.findNext("I", false, false); // find next: seq1/18
356 searchResults = f.getSearchResults();
357 assertEquals(searchResults.getSize(), 1);
358 match = searchResults.getResults().get(0);
359 assertSame(match.getSequence(), al.getSequenceAt(0));
360 assertEquals(match.getStart(), 18);
361 assertEquals(match.getEnd(), 18);
363 f.findNext("I", false, false); // find next: seq2/8
364 searchResults = f.getSearchResults();
365 assertEquals(searchResults.getSize(), 1);
366 match = searchResults.getResults().get(0);
367 assertSame(match.getSequence(), al.getSequenceAt(1));
368 assertEquals(match.getStart(), 8);
369 assertEquals(match.getEnd(), 8);
371 f.findNext("I", false, false);
372 assertTrue(f.getSearchResults().isEmpty());
375 * find should reset to start of alignment after a failed search
377 f.findNext("I", false, false); // find next: seq1/16
378 searchResults = f.getSearchResults();
379 assertEquals(searchResults.getSize(), 1);
380 match = searchResults.getResults().get(0);
381 assertSame(match.getSequence(), al.getSequenceAt(0));
382 assertEquals(match.getStart(), 16);
383 assertEquals(match.getEnd(), 16);
387 * Test for JAL-2302 to verify that sub-matches are not included in a find all
390 @Test(groups = "Functional")
391 public void testFind_maximalResultOnly()
393 Finder f = new Finder(av);
394 f.findAll("M+", false, false);
395 SearchResultsI searchResults = f.getSearchResults();
396 assertEquals(searchResults.getSize(), 1);
397 SearchResultMatchI match = searchResults.getResults().get(0);
398 assertSame(match.getSequence(), al.getSequenceAt(3));
399 assertEquals(match.getStart(), 4); // dataset sequence positions
400 assertEquals(match.getEnd(), 8); // base 1
404 * Test finding all matches of a sequence pattern in an alignment
406 @Test(groups = "Functional")
407 public void testFind_findAll()
409 Finder f = new Finder(av);
410 f.findAll("EfH", false, false);
411 SearchResultsI searchResults = f.getSearchResults();
412 assertEquals(searchResults.getSize(), 2);
413 SearchResultMatchI match = searchResults.getResults().get(0);
414 assertSame(match.getSequence(), al.getSequenceAt(1));
415 assertEquals(match.getStart(), 5);
416 assertEquals(match.getEnd(), 7);
417 match = searchResults.getResults().get(1);
418 assertSame(match.getSequence(), al.getSequenceAt(2));
419 assertEquals(match.getStart(), 4);
420 assertEquals(match.getEnd(), 6);
423 * find all I should find 2 positions in seq1, 1 in seq2
425 f.findAll("I", false, false);
426 searchResults = f.getSearchResults();
427 assertEquals(searchResults.getSize(), 3);
428 match = searchResults.getResults().get(0);
429 assertSame(match.getSequence(), al.getSequenceAt(0));
430 assertEquals(match.getStart(), 16);
431 assertEquals(match.getEnd(), 16);
432 match = searchResults.getResults().get(1);
433 assertSame(match.getSequence(), al.getSequenceAt(0));
434 assertEquals(match.getStart(), 18);
435 assertEquals(match.getEnd(), 18);
436 match = searchResults.getResults().get(2);
437 assertSame(match.getSequence(), al.getSequenceAt(1));
438 assertEquals(match.getStart(), 8);
439 assertEquals(match.getEnd(), 8);
443 * Test finding all matches, case-sensitive
445 @Test(groups = "Functional")
446 public void testFind_findAllCaseSensitive()
448 Finder f = new Finder(av);
451 * BC should match seq1/9-10 and seq2/2-3
453 f.findAll("BC", true, false);
454 SearchResultsI searchResults = f.getSearchResults();
455 assertEquals(searchResults.getSize(), 2);
456 SearchResultMatchI match = searchResults.getResults().get(0);
457 assertSame(match.getSequence(), al.getSequenceAt(0));
458 assertEquals(match.getStart(), 9);
459 assertEquals(match.getEnd(), 10);
460 match = searchResults.getResults().get(1);
461 assertSame(match.getSequence(), al.getSequenceAt(1));
462 assertEquals(match.getStart(), 2);
463 assertEquals(match.getEnd(), 3);
466 * bc should match seq3/1-2
469 f.findAll("bc", true, false);
470 searchResults = f.getSearchResults();
471 assertEquals(searchResults.getSize(), 1);
472 match = searchResults.getResults().get(0);
473 assertSame(match.getSequence(), al.getSequenceAt(2));
474 assertEquals(match.getStart(), 1);
475 assertEquals(match.getEnd(), 2);
477 f.findAll("bC", true, false);
478 assertTrue(f.getSearchResults().isEmpty());
482 * Test finding next match of a sequence pattern in a selection group
484 @Test(groups = "Functional")
485 public void testFind_inSelection()
488 * select sequences 2 and 3, columns 4-6 which contains
492 SequenceGroup sg = new SequenceGroup();
495 sg.addSequence(al.getSequenceAt(1), false);
496 sg.addSequence(al.getSequenceAt(2), false);
497 av.setSelectionGroup(sg);
499 FinderI f = new Finder(av);
500 f.findNext("b", false, false);
501 assertTrue(f.getIdMatches().isEmpty());
502 SearchResultsI searchResults = f.getSearchResults();
503 assertEquals(searchResults.getSize(), 1);
504 SearchResultMatchI match = searchResults.getResults().get(0);
505 assertSame(match.getSequence(), al.getSequenceAt(1));
506 assertEquals(match.getStart(), 2);
507 assertEquals(match.getEnd(), 2);
510 * a second Find should not return the 'b' in seq3 as outside the selection
512 f.findNext("b", false, false);
513 assertTrue(f.getSearchResults().isEmpty());
514 assertTrue(f.getIdMatches().isEmpty());
517 f.findNext("d", false, false);
518 assertTrue(f.getIdMatches().isEmpty());
519 searchResults = f.getSearchResults();
520 assertEquals(searchResults.getSize(), 1);
521 match = searchResults.getResults().get(0);
522 assertSame(match.getSequence(), al.getSequenceAt(1));
523 assertEquals(match.getStart(), 4);
524 assertEquals(match.getEnd(), 4);
525 f.findNext("d", false, false);
526 assertTrue(f.getIdMatches().isEmpty());
527 searchResults = f.getSearchResults();
528 assertEquals(searchResults.getSize(), 1);
529 match = searchResults.getResults().get(0);
530 assertSame(match.getSequence(), al.getSequenceAt(2));
531 assertEquals(match.getStart(), 3);
532 assertEquals(match.getEnd(), 3);
536 * Test finding all matches of a search pattern in a selection group
538 @Test(groups = "Functional")
539 public void testFind_findAllInSelection()
542 * select sequences 2 and 3, columns 4-6 which contains
546 SequenceGroup sg = new SequenceGroup();
549 sg.addSequence(al.getSequenceAt(1), false);
550 sg.addSequence(al.getSequenceAt(2), false);
551 av.setSelectionGroup(sg);
554 * search for 'e' should match two sequence ids and one residue
556 Finder f = new Finder(av);
557 f.findAll("e", false, false);
558 assertEquals(f.getIdMatches().size(), 2);
559 assertSame(f.getIdMatches().get(0), al.getSequenceAt(1));
560 assertSame(f.getIdMatches().get(1), al.getSequenceAt(2));
561 SearchResultsI searchResults = f.getSearchResults();
562 assertEquals(searchResults.getSize(), 1);
563 SearchResultMatchI match = searchResults.getResults().get(0);
564 assertSame(match.getSequence(), al.getSequenceAt(2));
565 assertEquals(match.getStart(), 4);
566 assertEquals(match.getEnd(), 4);
569 * search for 'Q' should match two sequence ids only
572 f.findAll("Q", false, false);
573 assertEquals(f.getIdMatches().size(), 2);
574 assertSame(f.getIdMatches().get(0), al.getSequenceAt(1));
575 assertSame(f.getIdMatches().get(1), al.getSequenceAt(2));
576 assertTrue(f.getSearchResults().isEmpty());
580 * Test finding in selection with a sequence too short to reach it
582 @Test(groups = "Functional")
583 public void testFind_findAllInSelectionWithShortSequence()
586 * select all sequences, columns 10-12
590 SequenceGroup sg = new SequenceGroup();
593 sg.addSequence(al.getSequenceAt(0), false);
594 sg.addSequence(al.getSequenceAt(1), false);
595 sg.addSequence(al.getSequenceAt(2), false);
596 sg.addSequence(al.getSequenceAt(3), false);
597 av.setSelectionGroup(sg);
600 * search for 'I' should match two sequence positions
602 Finder f = new Finder(av);
603 f.findAll("I", false, false);
604 assertTrue(f.getIdMatches().isEmpty());
605 SearchResultsI searchResults = f.getSearchResults();
606 assertEquals(searchResults.getSize(), 2);
607 SearchResultMatchI match = searchResults.getResults().get(0);
608 assertSame(match.getSequence(), al.getSequenceAt(0));
609 assertEquals(match.getStart(), 16);
610 assertEquals(match.getEnd(), 16);
611 match = searchResults.getResults().get(1);
612 assertSame(match.getSequence(), al.getSequenceAt(1));
613 assertEquals(match.getStart(), 8);
614 assertEquals(match.getEnd(), 8);
618 * Test that find does not report hidden positions
620 @Test(groups = "Functional")
621 public void testFind_withHiddenColumns()
632 * hide 2-4 (CD- -BC bcd ---)
634 HiddenColumns hc = new HiddenColumns();
635 hc.hideColumns(2, 4);
636 al.setHiddenColumns(hc);
639 * find all search for D should ignore hidden positions in seq1 and seq3,
640 * find the visible D in seq2
642 Finder f = new Finder(av);
643 f.findAll("D", false, false);
644 SearchResultsI searchResults = f.getSearchResults();
645 assertEquals(searchResults.getSize(), 1);
646 SearchResultMatchI match = searchResults.getResults().get(0);
647 assertSame(match.getSequence(), al.getSequenceAt(1));
648 assertEquals(match.getStart(), 4);
649 assertEquals(match.getEnd(), 4);
653 * find all 'aaa' should find end of seq4 only
655 hc.hideColumns(2, 5);
657 f.findAll("aaa", false, false);
658 searchResults = f.getSearchResults();
659 assertEquals(searchResults.getSize(), 1);
660 match = searchResults.getResults().get(0);
661 assertSame(match.getSequence(), al.getSequenceAt(3));
662 assertEquals(match.getStart(), 9);
663 assertEquals(match.getEnd(), 11);
666 * find all 'BE' should not match across hidden columns in seq1
668 f.findAll("BE", false, false);
669 assertTrue(f.getSearchResults().isEmpty());
672 * boundary case: hide columns at end of alignment
673 * search for H should match seq3/6 only
675 hc.revealAllHiddenColumns(new ColumnSelection());
676 hc.hideColumns(8, 13);
678 f.findNext("H", false, false);
679 searchResults = f.getSearchResults();
680 assertEquals(searchResults.getSize(), 1);
681 match = searchResults.getResults().get(0);
682 assertSame(match.getSequence(), al.getSequenceAt(2));
683 assertEquals(match.getStart(), 6);
684 assertEquals(match.getEnd(), 6);
687 @Test(groups = "Functional")
688 public void testFind_withHiddenColumnsAndSelection()
699 * hide columns 2-4 and 6-7
701 HiddenColumns hc = new HiddenColumns();
702 hc.hideColumns(2, 4);
703 hc.hideColumns(6, 7);
704 al.setHiddenColumns(hc);
709 SequenceGroup sg = new SequenceGroup();
710 sg.addSequence(al.getSequenceAt(1), false);
711 sg.addSequence(al.getSequenceAt(2), false);
714 av.setSelectionGroup(sg);
717 * find all search for A or H
718 * should match seq2/1, seq2/7, not seq3/6
720 Finder f = new Finder(av);
721 f.findAll("[AH]", false, false);
722 SearchResultsI searchResults = f.getSearchResults();
723 assertEquals(searchResults.getSize(), 2);
724 SearchResultMatchI match = searchResults.getResults().get(0);
725 assertSame(match.getSequence(), al.getSequenceAt(1));
726 assertEquals(match.getStart(), 1);
727 assertEquals(match.getEnd(), 1);
728 match = searchResults.getResults().get(1);
729 assertSame(match.getSequence(), al.getSequenceAt(1));
730 assertEquals(match.getStart(), 7);
731 assertEquals(match.getEnd(), 7);