/*
* Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
* Copyright (C) $$Year-Rel$$ The Jalview Authors
*
* This file is part of Jalview.
*
* Jalview is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* Jalview is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Jalview. If not, see .
* The Jalview Authors are detailed in the 'AUTHORS' file.
*/
package jalview.io.gff;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertNull;
import static org.testng.AssertJUnit.assertSame;
import static org.testng.AssertJUnit.assertTrue;
import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
import jalview.datamodel.AlignedCodonFrame;
import jalview.datamodel.Alignment;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.Mapping;
import jalview.datamodel.MappingType;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceDummy;
import jalview.datamodel.SequenceI;
import jalview.gui.AlignFrame;
import jalview.gui.JvOptionPane;
import jalview.io.DataSourceType;
import jalview.io.FileLoader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class ExonerateHelperTest
{
@BeforeClass(alwaysRun = true)
public void setUpJvOptionPane()
{
JvOptionPane.setInteractiveMode(false);
JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
}
@Test(groups = "Functional")
public void testGetMappingType()
{
// protein-to-dna:
assertSame(MappingType.PeptideToNucleotide,
ExonerateHelper
.getMappingType("exonerate:protein2genome:local"));
assertSame(MappingType.PeptideToNucleotide,
ExonerateHelper.getMappingType("exonerate:protein2dna:local"));
// dna-to-dna:
assertSame(MappingType.NucleotideToNucleotide,
ExonerateHelper.getMappingType("coding2coding"));
assertSame(MappingType.NucleotideToNucleotide,
ExonerateHelper.getMappingType("coding2genome"));
assertSame(MappingType.NucleotideToNucleotide,
ExonerateHelper.getMappingType("cdna2genome"));
assertSame(MappingType.NucleotideToNucleotide,
ExonerateHelper.getMappingType("genome2genome"));
assertNull(ExonerateHelper.getMappingType("affine:local"));
}
/**
* Test processing one exonerate GFF line for the case where the mapping is
* protein2dna, similarity feature is on the query (the protein), match to the
* forward strand, target sequence is in neither the alignment nor the 'new
* sequences'
*
* @throws IOException
*/
@Test(groups = "Functional")
public void testProcessGffSimilarity_protein2dna_forward_querygff()
throws IOException
{
ExonerateHelper testee = new ExonerateHelper();
List newseqs = new ArrayList();
String[] gff = "Seq\texonerate:protein2dna:local\tsimilarity\t3\t10\t.\t+\t.\talignment_id 0 ; Target dna1 ; Align 3 400 8"
.split("\\t");
SequenceI seq = new Sequence("Seq", "PQRASTGKEEDVMIWCHQN");
seq.createDatasetSequence();
AlignmentI align = new Alignment(new SequenceI[] {});
Map> set = Gff2Helper.parseNameValuePairs(gff[8]);
/*
* this should create a mapping from Seq2/3-10 to virtual sequence
* dna1 (added to newseqs) positions 400-423
*/
testee.processGffSimilarity(set, seq, gff, align, newseqs, false);
assertEquals(1, newseqs.size());
assertTrue(newseqs.get(0) instanceof SequenceDummy);
assertEquals("dna1", newseqs.get(0).getName());
assertEquals(1, align.getCodonFrames().size());
AlignedCodonFrame mapping = align.getCodonFrames().iterator().next();
assertEquals(1, mapping.getAaSeqs().length);
assertSame(seq.getDatasetSequence(), mapping.getAaSeqs()[0]);
assertEquals(1, mapping.getdnaSeqs().length);
assertSame(newseqs.get(0), mapping.getdnaSeqs()[0]);
assertEquals(1, mapping.getdnaToProt().length);
assertEquals(1, mapping.getdnaToProt()[0].getFromRanges().size());
assertArrayEquals(new int[] { 400, 423 }, mapping.getdnaToProt()[0]
.getFromRanges().get(0));
assertEquals(1, mapping.getdnaToProt()[0].getToRanges().size());
assertArrayEquals(new int[] { 3, 10 }, mapping.getdnaToProt()[0]
.getToRanges().get(0));
}
/**
* Test processing one exonerate GFF line for the case where the mapping is
* protein2dna, similarity feature is on the query (the protein), match to the
* reverse strand
*
* @throws IOException
*/
@Test(groups = "Functional")
public void testProcessGffSimilarity_protein2dna_reverse_querygff()
throws IOException
{
ExonerateHelper testee = new ExonerateHelper();
List newseqs = new ArrayList();
String[] gff = "Seq\texonerate:protein2dna:local\tsimilarity\t3\t10\t0\t-\t.\talignment_id 0 ; Target dna1 ; Align 3 400 8"
.split("\\t");
SequenceI seq = new Sequence("Seq", "PQRASTGKEEDVMIWCHQN");
seq.createDatasetSequence();
AlignmentI align = new Alignment(new SequenceI[] {});
Map> set = Gff2Helper.parseNameValuePairs(gff[8]);
/*
* this should create a mapping from Seq2/3-10 to virtual sequence
* dna1 (added to newseqs) positions 400-377 (reverse)
*/
testee.processGffSimilarity(set, seq, gff, align, newseqs, false);
assertEquals(1, newseqs.size());
assertTrue(newseqs.get(0) instanceof SequenceDummy);
assertEquals("dna1", newseqs.get(0).getName());
assertEquals(1, align.getCodonFrames().size());
AlignedCodonFrame mapping = align.getCodonFrames().iterator().next();
assertEquals(1, mapping.getAaSeqs().length);
assertSame(seq.getDatasetSequence(), mapping.getAaSeqs()[0]);
assertEquals(1, mapping.getdnaSeqs().length);
assertSame(newseqs.get(0), mapping.getdnaSeqs()[0]);
assertEquals(1, mapping.getdnaToProt().length);
assertEquals(1, mapping.getdnaToProt()[0].getFromRanges().size());
assertArrayEquals(new int[] { 400, 377 }, mapping.getdnaToProt()[0]
.getFromRanges().get(0));
assertEquals(1, mapping.getdnaToProt()[0].getToRanges().size());
assertArrayEquals(new int[] { 3, 10 }, mapping.getdnaToProt()[0]
.getToRanges().get(0));
}
/**
* Test processing one exonerate GFF line for the case where the mapping is
* protein2dna, similarity feature is on the target (the dna), match to the
* forward strand
*
* @throws IOException
*/
@Test(groups = "Functional")
public void testProcessGffSimilarity_protein2dna_forward_targetgff()
throws IOException
{
ExonerateHelper testee = new ExonerateHelper();
List newseqs = new ArrayList();
String[] gff = "dna1\texonerate:protein2dna:local\tsimilarity\t400\t423\t0\t+\t.\talignment_id 0 ; Query Prot1 ; Align 400 3 24"
.split("\\t");
SequenceI seq = new Sequence("dna1/391-430",
"CGATCCGATCCGATCCGATCCGATCCGATCCGATCCGATC");
seq.createDatasetSequence();
AlignmentI align = new Alignment(new SequenceI[] { seq });
// GFF feature on the target describes mapping from base 400 for
// count 24 to position 3
Map> set = Gff2Helper.parseNameValuePairs(gff[8]);
/*
* this should create a mapping from virtual sequence dna1 (added to
* newseqs) positions 400-423 to Prot1/3-10
*/
testee.processGffSimilarity(set, seq, gff, align, newseqs, false);
assertEquals(1, newseqs.size());
assertTrue(newseqs.get(0) instanceof SequenceDummy);
assertEquals("Prot1", newseqs.get(0).getName());
assertEquals(1, align.getCodonFrames().size());
AlignedCodonFrame mapping = align.getCodonFrames().iterator().next();
assertEquals(1, mapping.getAaSeqs().length);
assertSame(newseqs.get(0), mapping.getAaSeqs()[0]);
assertSame(seq.getDatasetSequence(), mapping.getdnaSeqs()[0]);
assertEquals(1, mapping.getdnaSeqs().length);
assertEquals(1, mapping.getdnaToProt().length);
assertEquals(1, mapping.getdnaToProt()[0].getFromRanges().size());
assertArrayEquals(new int[] { 400, 423 }, mapping.getdnaToProt()[0]
.getFromRanges().get(0));
assertEquals(1, mapping.getdnaToProt()[0].getToRanges().size());
assertArrayEquals(new int[] { 3, 10 }, mapping.getdnaToProt()[0]
.getToRanges().get(0));
}
/**
* Test processing one exonerate GFF line for the case where the mapping is
* protein2dna, similarity feature is on the target (the dna), match to the
* reverse strand
*
* @throws IOException
*/
@Test(groups = "Functional")
public void testProcessGffSimilarity_protein2dna_reverse_targetgff()
throws IOException
{
ExonerateHelper testee = new ExonerateHelper();
List newseqs = new ArrayList();
String[] gff = "dna1\texonerate:protein2dna:local\tsimilarity\t377\t400\t0\t-\t.\talignment_id 0 ; Query Prot1 ; Align 400 3 24"
.split("\\t");
SequenceI seq = new Sequence("dna1/371-410",
"CGATCCGATCCGATCCGATCCGATCCGATCCGATCCGATC");
seq.createDatasetSequence();
AlignmentI align = new Alignment(new SequenceI[] { seq });
// GFF feature on the target describes mapping from base 400 for
// count 24 to position 3
Map> set = Gff2Helper.parseNameValuePairs(gff[8]);
/*
* this should create a mapping from virtual sequence dna1 (added to
* newseqs) positions 400-377 (reverse) to Prot1/3-10
*/
testee.processGffSimilarity(set, seq, gff, align, newseqs, false);
assertEquals(1, newseqs.size());
assertTrue(newseqs.get(0) instanceof SequenceDummy);
assertEquals("Prot1", newseqs.get(0).getName());
assertEquals(1, align.getCodonFrames().size());
AlignedCodonFrame mapping = align.getCodonFrames().iterator().next();
assertEquals(1, mapping.getAaSeqs().length);
assertSame(newseqs.get(0), mapping.getAaSeqs()[0]);
assertSame(seq.getDatasetSequence(), mapping.getdnaSeqs()[0]);
assertEquals(1, mapping.getdnaSeqs().length);
assertEquals(1, mapping.getdnaToProt().length);
assertEquals(1, mapping.getdnaToProt()[0].getFromRanges().size());
assertArrayEquals(new int[] { 400, 377 }, mapping.getdnaToProt()[0]
.getFromRanges().get(0));
assertEquals(1, mapping.getdnaToProt()[0].getToRanges().size());
assertArrayEquals(new int[] { 3, 10 }, mapping.getdnaToProt()[0]
.getToRanges().get(0));
}
/**
* Tests loading exonerate GFF2 output, including 'similarity' alignment
* feature, on to sequences
*/
@Test(groups = { "Functional" })
public void testAddExonerateGffToAlignment()
{
FileLoader loader = new FileLoader(false);
AlignFrame af = loader.LoadFileWaitTillLoaded(
"examples/testdata/exonerateseqs.fa",
DataSourceType.FILE);
af.loadJalviewDataFile("examples/testdata/exonerateoutput.gff",
DataSourceType.FILE, null, null);
/*
* verify one mapping to a dummy sequence, one to a real one
*/
List mappings = af
.getViewport().getAlignment().getDataset().getCodonFrames();
assertEquals(2, mappings.size());
Iterator iter = mappings.iterator();
// first mapping is to dummy sequence
AlignedCodonFrame mapping = iter.next();
Mapping[] mapList = mapping.getProtMappings();
assertEquals(1, mapList.length);
assertTrue(mapList[0].getTo() instanceof SequenceDummy);
assertEquals("DDB_G0269124", mapList[0].getTo().getName());
// 143 in protein should map to codon [11270, 11269, 11268] in dna
int[] mappedRegion = mapList[0].getMap().locateInFrom(143, 143);
assertArrayEquals(new int[] { 11270, 11268 }, mappedRegion);
// second mapping is to a sequence in the alignment
mapping = iter.next();
mapList = mapping.getProtMappings();
assertEquals(1, mapList.length);
SequenceI proteinSeq = af.getViewport().getAlignment()
.findName("DDB_G0280897");
assertSame(proteinSeq.getDatasetSequence(), mapList[0].getTo());
assertEquals(1, mapping.getdnaToProt().length);
// 143 in protein should map to codon [11270, 11269, 11268] in dna
mappedRegion = mapList[0].getMap().locateInFrom(143, 143);
assertArrayEquals(new int[] { 11270, 11268 }, mappedRegion);
// 182 in protein should map to codon [11153, 11152, 11151] in dna
mappedRegion = mapList[0].getMap().locateInFrom(182, 182);
assertArrayEquals(new int[] { 11153, 11151 }, mappedRegion);
// and the reverse mapping:
mappedRegion = mapList[0].getMap().locateInTo(11151, 11153);
assertArrayEquals(new int[] { 182, 182 }, mappedRegion);
// 11150 in dna should _not_ map to protein
mappedRegion = mapList[0].getMap().locateInTo(11150, 11150);
assertNull(mappedRegion);
// similarly 183 in protein should _not_ map to dna
mappedRegion = mapList[0].getMap().locateInFrom(183, 183);
assertNull(mappedRegion);
}
}