JAL-3364 align split frame sequence panels with wrapped view scale left
[jalview.git] / test / jalview / io / gff / ExonerateHelperTest.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.io.gff;
22
23 import static org.testng.AssertJUnit.assertEquals;
24 import static org.testng.AssertJUnit.assertNull;
25 import static org.testng.AssertJUnit.assertSame;
26 import static org.testng.AssertJUnit.assertTrue;
27 import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
28
29 import jalview.datamodel.AlignedCodonFrame;
30 import jalview.datamodel.Alignment;
31 import jalview.datamodel.AlignmentI;
32 import jalview.datamodel.Mapping;
33 import jalview.datamodel.MappingType;
34 import jalview.datamodel.Sequence;
35 import jalview.datamodel.SequenceDummy;
36 import jalview.datamodel.SequenceI;
37 import jalview.gui.AlignFrame;
38 import jalview.gui.JvOptionPane;
39 import jalview.io.DataSourceType;
40 import jalview.io.FileLoader;
41
42 import java.io.IOException;
43 import java.util.ArrayList;
44 import java.util.Iterator;
45 import java.util.List;
46 import java.util.Map;
47
48 import org.testng.annotations.BeforeClass;
49 import org.testng.annotations.Test;
50
51 public class ExonerateHelperTest
52 {
53
54   @BeforeClass(alwaysRun = true)
55   public void setUpJvOptionPane()
56   {
57     JvOptionPane.setInteractiveMode(false);
58     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
59   }
60
61   @Test(groups = "Functional")
62   public void testGetMappingType()
63   {
64     // protein-to-dna:
65     assertSame(MappingType.PeptideToNucleotide,
66             ExonerateHelper
67                     .getMappingType("exonerate:protein2genome:local"));
68     assertSame(MappingType.PeptideToNucleotide,
69             ExonerateHelper.getMappingType("exonerate:protein2dna:local"));
70
71     // dna-to-dna:
72     assertSame(MappingType.NucleotideToNucleotide,
73             ExonerateHelper.getMappingType("coding2coding"));
74     assertSame(MappingType.NucleotideToNucleotide,
75             ExonerateHelper.getMappingType("coding2genome"));
76     assertSame(MappingType.NucleotideToNucleotide,
77             ExonerateHelper.getMappingType("cdna2genome"));
78     assertSame(MappingType.NucleotideToNucleotide,
79             ExonerateHelper.getMappingType("genome2genome"));
80     assertNull(ExonerateHelper.getMappingType("affine:local"));
81   }
82
83   /**
84    * Test processing one exonerate GFF line for the case where the mapping is
85    * protein2dna, similarity feature is on the query (the protein), match to the
86    * forward strand, target sequence is in neither the alignment nor the 'new
87    * sequences'
88    * 
89    * @throws IOException
90    */
91   @Test(groups = "Functional")
92   public void testProcessGffSimilarity_protein2dna_forward_querygff()
93           throws IOException
94   {
95     ExonerateHelper testee = new ExonerateHelper();
96     List<SequenceI> newseqs = new ArrayList<SequenceI>();
97     String[] gff = "Seq\texonerate:protein2dna:local\tsimilarity\t3\t10\t.\t+\t.\talignment_id 0 ; Target dna1 ; Align 3 400 8"
98             .split("\\t");
99     SequenceI seq = new Sequence("Seq", "PQRASTGKEEDVMIWCHQN");
100     seq.createDatasetSequence();
101     AlignmentI align = new Alignment(new SequenceI[] {});
102     Map<String, List<String>> set = Gff2Helper.parseNameValuePairs(gff[8]);
103
104     /*
105      * this should create a mapping from Seq2/3-10 to virtual sequence
106      * dna1 (added to newseqs) positions 400-423
107      */
108     testee.processGffSimilarity(set, seq, gff, align, newseqs, false);
109     assertEquals(1, newseqs.size());
110     assertTrue(newseqs.get(0) instanceof SequenceDummy);
111     assertEquals("dna1", newseqs.get(0).getName());
112     assertEquals(1, align.getCodonFrames().size());
113     AlignedCodonFrame mapping = align.getCodonFrames().iterator().next();
114     assertEquals(1, mapping.getAaSeqs().length);
115     assertSame(seq.getDatasetSequence(), mapping.getAaSeqs()[0]);
116     assertEquals(1, mapping.getdnaSeqs().length);
117     assertSame(newseqs.get(0), mapping.getdnaSeqs()[0]);
118     assertEquals(1, mapping.getdnaToProt().length);
119     assertEquals(1, mapping.getdnaToProt()[0].getFromRanges().size());
120     assertArrayEquals(new int[] { 400, 423 }, mapping.getdnaToProt()[0]
121             .getFromRanges().get(0));
122     assertEquals(1, mapping.getdnaToProt()[0].getToRanges().size());
123     assertArrayEquals(new int[] { 3, 10 }, mapping.getdnaToProt()[0]
124             .getToRanges().get(0));
125   }
126
127   /**
128    * Test processing one exonerate GFF line for the case where the mapping is
129    * protein2dna, similarity feature is on the query (the protein), match to the
130    * reverse strand
131    * 
132    * @throws IOException
133    */
134   @Test(groups = "Functional")
135   public void testProcessGffSimilarity_protein2dna_reverse_querygff()
136           throws IOException
137   {
138     ExonerateHelper testee = new ExonerateHelper();
139     List<SequenceI> newseqs = new ArrayList<SequenceI>();
140     String[] gff = "Seq\texonerate:protein2dna:local\tsimilarity\t3\t10\t0\t-\t.\talignment_id 0 ; Target dna1 ; Align 3 400 8"
141             .split("\\t");
142     SequenceI seq = new Sequence("Seq", "PQRASTGKEEDVMIWCHQN");
143     seq.createDatasetSequence();
144     AlignmentI align = new Alignment(new SequenceI[] {});
145     Map<String, List<String>> set = Gff2Helper.parseNameValuePairs(gff[8]);
146
147     /*
148      * this should create a mapping from Seq2/3-10 to virtual sequence
149      * dna1 (added to newseqs) positions 400-377 (reverse)
150      */
151     testee.processGffSimilarity(set, seq, gff, align, newseqs, false);
152     assertEquals(1, newseqs.size());
153     assertTrue(newseqs.get(0) instanceof SequenceDummy);
154     assertEquals("dna1", newseqs.get(0).getName());
155     assertEquals(1, align.getCodonFrames().size());
156     AlignedCodonFrame mapping = align.getCodonFrames().iterator().next();
157     assertEquals(1, mapping.getAaSeqs().length);
158     assertSame(seq.getDatasetSequence(), mapping.getAaSeqs()[0]);
159     assertEquals(1, mapping.getdnaSeqs().length);
160     assertSame(newseqs.get(0), mapping.getdnaSeqs()[0]);
161     assertEquals(1, mapping.getdnaToProt().length);
162     assertEquals(1, mapping.getdnaToProt()[0].getFromRanges().size());
163     assertArrayEquals(new int[] { 400, 377 }, mapping.getdnaToProt()[0]
164             .getFromRanges().get(0));
165     assertEquals(1, mapping.getdnaToProt()[0].getToRanges().size());
166     assertArrayEquals(new int[] { 3, 10 }, mapping.getdnaToProt()[0]
167             .getToRanges().get(0));
168   }
169
170   /**
171    * Test processing one exonerate GFF line for the case where the mapping is
172    * protein2dna, similarity feature is on the target (the dna), match to the
173    * forward strand
174    * 
175    * @throws IOException
176    */
177   @Test(groups = "Functional")
178   public void testProcessGffSimilarity_protein2dna_forward_targetgff()
179           throws IOException
180   {
181     ExonerateHelper testee = new ExonerateHelper();
182     List<SequenceI> newseqs = new ArrayList<SequenceI>();
183     String[] gff = "dna1\texonerate:protein2dna:local\tsimilarity\t400\t423\t0\t+\t.\talignment_id 0 ; Query Prot1 ; Align 400 3 24"
184             .split("\\t");
185     SequenceI seq = new Sequence("dna1/391-430",
186             "CGATCCGATCCGATCCGATCCGATCCGATCCGATCCGATC");
187     seq.createDatasetSequence();
188     AlignmentI align = new Alignment(new SequenceI[] { seq });
189     // GFF feature on the target describes mapping from base 400 for
190     // count 24 to position 3
191     Map<String, List<String>> set = Gff2Helper.parseNameValuePairs(gff[8]);
192
193     /*
194      * this should create a mapping from virtual sequence dna1 (added to 
195      * newseqs) positions 400-423 to Prot1/3-10
196      */
197     testee.processGffSimilarity(set, seq, gff, align, newseqs, false);
198     assertEquals(1, newseqs.size());
199     assertTrue(newseqs.get(0) instanceof SequenceDummy);
200     assertEquals("Prot1", newseqs.get(0).getName());
201     assertEquals(1, align.getCodonFrames().size());
202     AlignedCodonFrame mapping = align.getCodonFrames().iterator().next();
203     assertEquals(1, mapping.getAaSeqs().length);
204     assertSame(newseqs.get(0), mapping.getAaSeqs()[0]);
205     assertSame(seq.getDatasetSequence(), mapping.getdnaSeqs()[0]);
206     assertEquals(1, mapping.getdnaSeqs().length);
207     assertEquals(1, mapping.getdnaToProt().length);
208     assertEquals(1, mapping.getdnaToProt()[0].getFromRanges().size());
209     assertArrayEquals(new int[] { 400, 423 }, mapping.getdnaToProt()[0]
210             .getFromRanges().get(0));
211     assertEquals(1, mapping.getdnaToProt()[0].getToRanges().size());
212     assertArrayEquals(new int[] { 3, 10 }, mapping.getdnaToProt()[0]
213             .getToRanges().get(0));
214   }
215
216   /**
217    * Test processing one exonerate GFF line for the case where the mapping is
218    * protein2dna, similarity feature is on the target (the dna), match to the
219    * reverse strand
220    * 
221    * @throws IOException
222    */
223   @Test(groups = "Functional")
224   public void testProcessGffSimilarity_protein2dna_reverse_targetgff()
225           throws IOException
226   {
227     ExonerateHelper testee = new ExonerateHelper();
228     List<SequenceI> newseqs = new ArrayList<SequenceI>();
229     String[] gff = "dna1\texonerate:protein2dna:local\tsimilarity\t377\t400\t0\t-\t.\talignment_id 0 ; Query Prot1 ; Align 400 3 24"
230             .split("\\t");
231     SequenceI seq = new Sequence("dna1/371-410",
232             "CGATCCGATCCGATCCGATCCGATCCGATCCGATCCGATC");
233     seq.createDatasetSequence();
234     AlignmentI align = new Alignment(new SequenceI[] { seq });
235     // GFF feature on the target describes mapping from base 400 for
236     // count 24 to position 3
237     Map<String, List<String>> set = Gff2Helper.parseNameValuePairs(gff[8]);
238
239     /*
240      * this should create a mapping from virtual sequence dna1 (added to 
241      * newseqs) positions 400-377 (reverse) to Prot1/3-10
242      */
243     testee.processGffSimilarity(set, seq, gff, align, newseqs, false);
244     assertEquals(1, newseqs.size());
245     assertTrue(newseqs.get(0) instanceof SequenceDummy);
246     assertEquals("Prot1", newseqs.get(0).getName());
247     assertEquals(1, align.getCodonFrames().size());
248     AlignedCodonFrame mapping = align.getCodonFrames().iterator().next();
249     assertEquals(1, mapping.getAaSeqs().length);
250     assertSame(newseqs.get(0), mapping.getAaSeqs()[0]);
251     assertSame(seq.getDatasetSequence(), mapping.getdnaSeqs()[0]);
252     assertEquals(1, mapping.getdnaSeqs().length);
253     assertEquals(1, mapping.getdnaToProt().length);
254     assertEquals(1, mapping.getdnaToProt()[0].getFromRanges().size());
255     assertArrayEquals(new int[] { 400, 377 }, mapping.getdnaToProt()[0]
256             .getFromRanges().get(0));
257     assertEquals(1, mapping.getdnaToProt()[0].getToRanges().size());
258     assertArrayEquals(new int[] { 3, 10 }, mapping.getdnaToProt()[0]
259             .getToRanges().get(0));
260   }
261
262   /**
263    * Tests loading exonerate GFF2 output, including 'similarity' alignment
264    * feature, on to sequences
265    */
266   @Test(groups = { "Functional" })
267   public void testAddExonerateGffToAlignment()
268   {
269     FileLoader loader = new FileLoader(false);
270     AlignFrame af = loader.LoadFileWaitTillLoaded(
271             "examples/testdata/exonerateseqs.fa",
272             DataSourceType.FILE);
273   
274     af.loadJalviewDataFile("examples/testdata/exonerateoutput.gff",
275             DataSourceType.FILE, null, null);
276   
277     /*
278      * verify one mapping to a dummy sequence, one to a real one
279      */
280     List<AlignedCodonFrame> mappings = af
281             .getViewport().getAlignment().getDataset().getCodonFrames();
282     assertEquals(2, mappings.size());
283     Iterator<AlignedCodonFrame> iter = mappings.iterator();
284   
285     // first mapping is to dummy sequence
286     AlignedCodonFrame mapping = iter.next();
287     Mapping[] mapList = mapping.getProtMappings();
288     assertEquals(1, mapList.length);
289     assertTrue(mapList[0].getTo() instanceof SequenceDummy);
290     assertEquals("DDB_G0269124", mapList[0].getTo().getName());
291
292     // 143 in protein should map to codon [11270, 11269, 11268] in dna
293     int[] mappedRegion = mapList[0].getMap().locateInFrom(143, 143);
294     assertArrayEquals(new int[] { 11270, 11268 }, mappedRegion);
295   
296     // second mapping is to a sequence in the alignment
297     mapping = iter.next();
298     mapList = mapping.getProtMappings();
299     assertEquals(1, mapList.length);
300     SequenceI proteinSeq = af.getViewport().getAlignment()
301             .findName("DDB_G0280897");
302     assertSame(proteinSeq.getDatasetSequence(), mapList[0].getTo());
303     assertEquals(1, mapping.getdnaToProt().length);
304   
305     // 143 in protein should map to codon [11270, 11269, 11268] in dna
306     mappedRegion = mapList[0].getMap().locateInFrom(143, 143);
307     assertArrayEquals(new int[] { 11270, 11268 }, mappedRegion);
308   
309     // 182 in protein should map to codon [11153, 11152, 11151] in dna
310     mappedRegion = mapList[0].getMap().locateInFrom(182, 182);
311     assertArrayEquals(new int[] { 11153, 11151 }, mappedRegion);
312   
313     // and the reverse mapping:
314     mappedRegion = mapList[0].getMap().locateInTo(11151, 11153);
315     assertArrayEquals(new int[] { 182, 182 }, mappedRegion);
316   
317     // 11150 in dna should _not_ map to protein
318     mappedRegion = mapList[0].getMap().locateInTo(11150, 11150);
319     assertNull(mappedRegion);
320   
321     // similarly 183 in protein should _not_ map to dna
322     mappedRegion = mapList[0].getMap().locateInFrom(183, 183);
323     assertNull(mappedRegion);
324   }
325 }