771712d691ac421c5476d1482d4beda1e8246839
[jalview.git] / test / jalview / analysis / FinderTest.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
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.
11  *  
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.
16  * 
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.
20  */
21 package jalview.analysis;
22
23 import static org.testng.Assert.assertEquals;
24 import static org.testng.Assert.assertSame;
25 import static org.testng.Assert.assertTrue;
26
27 import jalview.bin.Cache;
28 import jalview.datamodel.Alignment;
29 import jalview.datamodel.AlignmentI;
30 import jalview.datamodel.SearchResultMatchI;
31 import jalview.datamodel.SearchResultsI;
32 import jalview.datamodel.Sequence;
33 import jalview.datamodel.SequenceGroup;
34 import jalview.gui.AlignFrame;
35 import jalview.gui.JvOptionPane;
36 import jalview.io.DataSourceType;
37 import jalview.io.FileLoader;
38
39 import java.util.List;
40
41 import org.testng.annotations.BeforeClass;
42 import org.testng.annotations.Test;
43
44 public class FinderTest
45 {
46   @BeforeClass(alwaysRun = true)
47   public void setUpJvOptionPane()
48   {
49     JvOptionPane.setInteractiveMode(false);
50     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
51   }
52
53   private AlignFrame af;
54
55   private AlignmentI al;
56
57   @BeforeClass(groups = "Functional")
58   public void setUp()
59   {
60     Cache.loadProperties("test/jalview/io/testProps.jvprops");
61     Cache.applicationProperties.setProperty("PAD_GAPS",
62             Boolean.FALSE.toString());
63
64     String seqData = "seq1seq1/8-16 ABCD--EF-GHI\n" + "seq2 A--BCDefHI\n"
65             + "seq3 --bcdEFH\n" + "seq4 aa---aMMMMMaaa\n";
66     af = new FileLoader().LoadFileWaitTillLoaded(seqData,
67             DataSourceType.PASTE);
68     al = af.getViewport().getAlignment();
69   }
70
71   /**
72    * Test for find matches of a regular expression
73    */
74   @Test(groups = "Functional")
75   public void testFind_regex()
76   {
77     /*
78      * find next match only
79      */
80     Finder f = new Finder(al, null);
81     f.find("E.H"); // 'E, any character, H'
82     // should match seq2 efH only
83     SearchResultsI sr = f.getSearchResults();
84     assertEquals(sr.getSize(), 1);
85     List<SearchResultMatchI> matches = sr.getResults();
86     assertSame(al.getSequenceAt(1), matches.get(0).getSequence());
87     assertEquals(matches.get(0).getStart(), 5);
88     assertEquals(matches.get(0).getEnd(), 7);
89
90     f = new Finder(al, null);
91     f.setFindAll(true);
92     f.find("E.H"); // 'E, any character, H'
93     // should match seq2 efH and seq3 EFH
94     sr = f.getSearchResults();
95     assertEquals(sr.getSize(), 2);
96     matches = sr.getResults();
97     assertSame(al.getSequenceAt(1), matches.get(0).getSequence());
98     assertSame(al.getSequenceAt(2), matches.get(1).getSequence());
99     assertEquals(matches.get(0).getStart(), 5);
100     assertEquals(matches.get(0).getEnd(), 7);
101     assertEquals(matches.get(1).getStart(), 4);
102     assertEquals(matches.get(1).getEnd(), 6);
103   }
104
105   /**
106    * Test for (undocumented) find residue by position
107    */
108   @Test(groups = "Functional")
109   public void testFind_residueNumber()
110   {
111     Finder f = new Finder(al, null);
112
113     /*
114      * find first match should return seq1 residue 9
115      */
116     f.find("9");
117     SearchResultsI sr = f.getSearchResults();
118     assertEquals(sr.getSize(), 1);
119     List<SearchResultMatchI> matches = sr.getResults();
120     assertSame(al.getSequenceAt(0), matches.get(0).getSequence());
121     assertEquals(matches.get(0).getStart(), 9);
122     assertEquals(matches.get(0).getEnd(), 9);
123
124     /*
125      * find all matches should return seq1 and seq4 (others are too short)
126      */
127     f = new Finder(al, null);
128     f.setFindAll(true);
129     f.find("9");
130     sr = f.getSearchResults();
131     assertEquals(sr.getSize(), 2);
132     matches = sr.getResults();
133     assertSame(al.getSequenceAt(0), matches.get(0).getSequence());
134     assertSame(al.getSequenceAt(3), matches.get(1).getSequence());
135     assertEquals(matches.get(0).getStart(), 9);
136     assertEquals(matches.get(0).getEnd(), 9);
137     assertEquals(matches.get(1).getStart(), 9);
138     assertEquals(matches.get(1).getEnd(), 9);
139
140     /*
141      * parsing of search string as integer is strict
142      */
143     f = new Finder(al, null);
144     f.find(" 9");
145     assertTrue(f.getSearchResults().isEmpty());
146   }
147
148   /**
149    * Test for find next action
150    */
151   @Test(groups = "Functional")
152   public void testFindNext()
153   {
154     /*
155      * start at second sequence; resIndex of -1
156      * means sequence id / description is searched
157      */
158     Finder f = new Finder(al, null, 1, -1);
159     f.find("e"); // matches id
160
161     assertTrue(f.getSearchResults().isEmpty());
162     assertEquals(f.getIdMatch().size(), 1);
163     assertSame(f.getIdMatch().get(0), al.getSequenceAt(1));
164
165     // resIndex is now 0 - for use in next find next
166     assertEquals(f.getResIndex(), 0);
167     f = new Finder(al, null, 1, 0);
168     f.find("e"); // matches in sequence
169     assertTrue(f.getIdMatch().isEmpty());
170     assertEquals(f.getSearchResults().getSize(), 1);
171     List<SearchResultMatchI> matches = f.getSearchResults().getResults();
172     assertEquals(matches.get(0).getStart(), 5);
173     assertEquals(matches.get(0).getEnd(), 5);
174     assertSame(matches.get(0).getSequence(), al.getSequenceAt(1));
175     // still in the second sequence
176     assertEquals(f.getSeqIndex(), 1);
177     // next residue position to search from is 5
178     // (used as base 0 by RegEx so the same as 6 if base 1)
179     assertEquals(f.getResIndex(), 5);
180
181     // find next from end of sequence - finds next sequence id
182     f = new Finder(al, null, 1, 5);
183     f.find("e");
184     assertEquals(f.getIdMatch().size(), 1);
185     assertSame(f.getIdMatch().get(0), al.getSequenceAt(2));
186   }
187
188   /**
189    * Test for matching within sequence descriptions
190    */
191   @Test(groups = "Functional")
192   public void testFind_inDescription()
193   {
194     AlignmentI al2 = new Alignment(al);
195     al2.getSequenceAt(0).setDescription("BRAF");
196     al2.getSequenceAt(1).setDescription("braf");
197
198     /*
199      * find first match only
200      */
201     Finder f = new Finder(al2, null);
202     f.setIncludeDescription(true);
203     f.find("rAF");
204     assertEquals(f.getIdMatch().size(), 1);
205     assertSame(f.getIdMatch().get(0), al2.getSequenceAt(0));
206     assertTrue(f.getSearchResults().isEmpty());
207
208     /*
209      * find all matches
210      */
211     f = new Finder(al2, null);
212     f.setFindAll(true);
213     f.setIncludeDescription(true);
214     f.find("rAF");
215     assertEquals(f.getIdMatch().size(), 2);
216     assertSame(f.getIdMatch().get(0), al2.getSequenceAt(0));
217     assertSame(f.getIdMatch().get(1), al2.getSequenceAt(1));
218     assertTrue(f.getSearchResults().isEmpty());
219
220     /*
221      * case sensitive
222      */
223     f = new Finder(al2, null);
224     f.setFindAll(true);
225     f.setCaseSensitive(true);
226     f.setIncludeDescription(true);
227
228     f.find("RAF");
229     assertEquals(f.getIdMatch().size(), 1);
230     assertSame(f.getIdMatch().get(0), al2.getSequenceAt(0));
231     assertTrue(f.getSearchResults().isEmpty());
232
233     /*
234      * match sequence id, description and sequence!
235      */
236     al2.getSequenceAt(0).setDescription("the efh sequence");
237     al2.getSequenceAt(0).setName("mouseEFHkinase");
238     al2.getSequenceAt(1).setName("humanEFHkinase");
239     f = new Finder(al2, null);
240     f.setFindAll(true);
241     f.setIncludeDescription(true);
242
243     /*
244      * sequence matches should have no duplicates
245      */
246     f.find("EFH");
247     assertEquals(f.getIdMatch().size(), 2);
248     assertSame(f.getIdMatch().get(0), al2.getSequenceAt(0));
249     assertSame(f.getIdMatch().get(1), al2.getSequenceAt(1));
250
251     assertEquals(f.getSearchResults().getSize(), 2);
252     SearchResultMatchI match = f.getSearchResults().getResults().get(0);
253     assertSame(al2.getSequenceAt(1), match.getSequence());
254     assertEquals(5, match.getStart());
255     assertEquals(7, match.getEnd());
256     match = f.getSearchResults().getResults().get(1);
257     assertSame(al2.getSequenceAt(2), match.getSequence());
258     assertEquals(4, match.getStart());
259     assertEquals(6, match.getEnd());
260   }
261
262   /**
263    * Test for matching within sequence ids
264    */
265   @Test(groups = "Functional")
266   public void testFindAll_sequenceIds()
267   {
268     Finder f = new Finder(al, null);
269     f.setFindAll(true);
270
271     /*
272      * case insensitive; seq1 occurs twice in sequence id but
273      * only one match should be returned
274      */
275     f.find("SEQ1");
276     assertEquals(f.getIdMatch().size(), 1);
277     assertSame(f.getIdMatch().get(0), al.getSequenceAt(0));
278     assertTrue(f.getSearchResults().isEmpty());
279
280     /*
281      * case sensitive
282      */
283     f = new Finder(al, null);
284     f.setFindAll(true);
285     f.setCaseSensitive(true);
286     f.find("SEQ1");
287     assertTrue(f.getSearchResults().isEmpty());
288
289     /*
290      * match both sequence id and sequence
291      */
292     AlignmentI al2 = new Alignment(al);
293     al2.addSequence(new Sequence("aBz", "xyzabZpqrAbZ"));
294     f = new Finder(al2, null);
295     f.setFindAll(true);
296     f.find("ABZ");
297     assertEquals(f.getIdMatch().size(), 1);
298     assertSame(f.getIdMatch().get(0), al2.getSequenceAt(4));
299     assertEquals(f.getSearchResults().getSize(), 2);
300     SearchResultMatchI match = f.getSearchResults().getResults().get(0);
301     assertSame(al2.getSequenceAt(4), match.getSequence());
302     assertEquals(4, match.getStart());
303     assertEquals(6, match.getEnd());
304     match = f.getSearchResults().getResults().get(1);
305     assertSame(al2.getSequenceAt(4), match.getSequence());
306     assertEquals(10, match.getStart());
307     assertEquals(12, match.getEnd());
308   }
309
310   /**
311    * Test finding next match of a sequence pattern in an alignment
312    */
313   @Test(groups = "Functional")
314   public void testFind()
315   {
316     Finder f = new Finder(al, null);
317     f.find("EfH");
318     SearchResultsI searchResults = f.getSearchResults();
319     assertEquals(searchResults.getSize(), 1);
320     SearchResultMatchI match = searchResults.getResults().get(0);
321     assertSame(al.getSequenceAt(1), match.getSequence());
322     assertEquals(5, match.getStart());
323     assertEquals(7, match.getEnd());
324   }
325
326   /**
327    * Test for JAL-2302 to verify that sub-matches are not included in a find all
328    * result
329    */
330   @Test(groups = "Functional")
331   public void testFind_maximalResultOnly()
332   {
333     Finder f = new Finder(al, null);
334     f.setFindAll(true);
335     f.find("M+");
336     SearchResultsI searchResults = f.getSearchResults();
337     assertEquals(searchResults.getSize(), 1);
338     SearchResultMatchI match = searchResults.getResults().get(0);
339     assertSame(al.getSequenceAt(3), match.getSequence());
340     assertEquals(4, match.getStart()); // dataset sequence positions
341     assertEquals(8, match.getEnd()); // base 1
342   }
343
344   /**
345    * Test finding all matches of a sequence pattern in an alignment
346    */
347   @Test(groups = "Functional")
348   public void testFind_findAll()
349   {
350     Finder f = new Finder(al, null);
351     f.setFindAll(true);
352     f.find("EfH");
353     SearchResultsI searchResults = f.getSearchResults();
354     assertEquals(searchResults.getSize(), 2);
355     SearchResultMatchI match = searchResults.getResults().get(0);
356     assertSame(al.getSequenceAt(1), match.getSequence());
357     assertEquals(5, match.getStart());
358     assertEquals(7, match.getEnd());
359     match = searchResults.getResults().get(1);
360     assertSame(al.getSequenceAt(2), match.getSequence());
361     assertEquals(4, match.getStart());
362     assertEquals(6, match.getEnd());
363   }
364
365   /**
366    * Test finding all matches, case-sensitive
367    */
368   @Test(groups = "Functional")
369   public void testFind_findAllCaseSensitive()
370   {
371     Finder f = new Finder(al, null);
372     f.setCaseSensitive(true);
373     f.setFindAll(true);
374     f.find("BC");
375     SearchResultsI searchResults = f.getSearchResults();
376     assertEquals(searchResults.getSize(), 2);
377     SearchResultMatchI match = searchResults.getResults().get(0);
378     assertSame(al.getSequenceAt(0), match.getSequence());
379     assertEquals(match.getStart(), 9);
380     assertEquals(match.getEnd(), 10);
381     match = searchResults.getResults().get(1);
382     assertSame(al.getSequenceAt(1), match.getSequence());
383     assertEquals(match.getStart(), 2);
384     assertEquals(match.getEnd(), 3);
385   }
386
387   /**
388    * Test finding next match of a sequence pattern in a selection group
389    */
390   @Test(groups = "Functional")
391   public void testFind_inSelection()
392   {
393     /*
394      * select sequences 2 and 3, columns 4-6 which contains
395      * BCD
396      * cdE
397      */
398     SequenceGroup sg = new SequenceGroup();
399     sg.setStartRes(3);
400     sg.setEndRes(5);
401     sg.addSequence(al.getSequenceAt(1), false);
402     sg.addSequence(al.getSequenceAt(2), false);
403
404     Finder f = new Finder(al, sg);
405     f.find("b");
406     assertTrue(f.getIdMatch().isEmpty());
407     SearchResultsI searchResults = f.getSearchResults();
408     assertEquals(searchResults.getSize(), 1);
409     SearchResultMatchI match = searchResults.getResults().get(0);
410     assertSame(al.getSequenceAt(1), match.getSequence());
411     assertEquals(2, match.getStart());
412     assertEquals(2, match.getEnd());
413
414     /*
415      * a second Find should not return the 'b' in seq3 as outside the selection
416      */
417     f.find("b");
418     assertTrue(f.getSearchResults().isEmpty());
419     assertTrue(f.getIdMatch().isEmpty());
420
421     f = new Finder(al, sg);
422     f.find("d");
423     assertTrue(f.getIdMatch().isEmpty());
424     searchResults = f.getSearchResults();
425     assertEquals(searchResults.getSize(), 1);
426     match = searchResults.getResults().get(0);
427     assertSame(al.getSequenceAt(1), match.getSequence());
428     assertEquals(4, match.getStart());
429     assertEquals(4, match.getEnd());
430     f.find("d");
431     assertTrue(f.getIdMatch().isEmpty());
432     searchResults = f.getSearchResults();
433     assertEquals(searchResults.getSize(), 1);
434     match = searchResults.getResults().get(0);
435     assertSame(al.getSequenceAt(2), match.getSequence());
436     assertEquals(3, match.getStart());
437     assertEquals(3, match.getEnd());
438   }
439
440   /**
441    * Test finding all matches of a search pattern in a selection group
442    */
443   @Test(groups = "Functional")
444   public void testFind_findAllInSelection()
445   {
446     /*
447      * select sequences 2 and 3, columns 4-6 which contains
448      * BCD
449      * cdE
450      */
451     SequenceGroup sg = new SequenceGroup();
452     sg.setStartRes(3);
453     sg.setEndRes(5);
454     sg.addSequence(al.getSequenceAt(1), false);
455     sg.addSequence(al.getSequenceAt(2), false);
456   
457     /*
458      * search for 'e' should match two sequence ids and one residue
459      */
460     Finder f = new Finder(al, sg);
461     f.setFindAll(true);
462     f.find("e");
463     assertEquals(f.getIdMatch().size(), 2);
464     assertSame(f.getIdMatch().get(0), al.getSequenceAt(1));
465     assertSame(f.getIdMatch().get(1), al.getSequenceAt(2));
466     SearchResultsI searchResults = f.getSearchResults();
467     assertEquals(searchResults.getSize(), 1);
468     SearchResultMatchI match = searchResults.getResults().get(0);
469     assertSame(al.getSequenceAt(2), match.getSequence());
470     assertEquals(4, match.getStart());
471     assertEquals(4, match.getEnd());
472
473     /*
474      * search for 'Q' should match two sequence ids only
475      */
476     f = new Finder(al, sg);
477     f.setFindAll(true);
478     f.find("Q");
479     assertEquals(f.getIdMatch().size(), 2);
480     assertSame(f.getIdMatch().get(0), al.getSequenceAt(1));
481     assertSame(f.getIdMatch().get(1), al.getSequenceAt(2));
482     assertTrue(f.getSearchResults().isEmpty());
483   }
484
485   /**
486    * Test finding in selection with a sequence too short to reach it
487    */
488   @Test(groups = "Functional")
489   public void testFind_findAllInSelectionWithShortSequence()
490   {
491     /*
492      * select all sequences, columns 10-12
493      * BCD
494      * cdE
495      */
496     SequenceGroup sg = new SequenceGroup();
497     sg.setStartRes(9);
498     sg.setEndRes(11);
499     sg.addSequence(al.getSequenceAt(0), false);
500     sg.addSequence(al.getSequenceAt(1), false);
501     sg.addSequence(al.getSequenceAt(2), false);
502     sg.addSequence(al.getSequenceAt(3), false);
503   
504     /*
505      * search for 'I' should match two sequence positions
506      */
507     Finder f = new Finder(al, sg);
508     f.setFindAll(true);
509     f.find("I");
510     assertTrue(f.getIdMatch().isEmpty());
511     SearchResultsI searchResults = f.getSearchResults();
512     assertEquals(searchResults.getSize(), 2);
513     SearchResultMatchI match = searchResults.getResults().get(0);
514     assertSame(al.getSequenceAt(0), match.getSequence());
515     assertEquals(16, match.getStart());
516     assertEquals(16, match.getEnd());
517     match = searchResults.getResults().get(1);
518     assertSame(al.getSequenceAt(1), match.getSequence());
519     assertEquals(8, match.getStart());
520     assertEquals(8, match.getEnd());
521   }
522 }