JAL-1619 refactoring in progress for Dna translation
[jalview.git] / test / jalview / analysis / DnaTest.java
1 package jalview.analysis;
2
3 import static org.junit.Assert.assertEquals;
4 import jalview.datamodel.AlignmentI;
5 import jalview.datamodel.ColumnSelection;
6 import jalview.io.FormatAdapter;
7
8 import java.io.IOException;
9 import java.util.Arrays;
10
11 import org.junit.Test;
12
13 public class DnaTest
14 {
15   // AA encoding codons as ordered on the Jalview help page Amino Acid Table
16   private static String fasta = ">B\n" + "GCT" + "GCC" + "GCA" + "GCG"
17           + "TGT" + "TGC" + "GAT" + "GAC" + "GAA" + "GAG" + "TTT" + "TTC"
18           + "GGT" + "GGC" + "GGA" + "GGG" + "CAT" + "CAC" + "ATT" + "ATC"
19           + "ATA" + "AAA" + "AAG" + "TTG" + "TTA" + "CTT" + "CTC" + "CTA"
20           + "CTG" + "ATG" + "AAT" + "AAC" + "CCT" + "CCC" + "CCA" + "CCG"
21           + "CAA" + "CAG" + "CGT" + "CGC" + "CGA" + "CGG" + "AGA" + "AGG"
22           + "TCT" + "TCC" + "TCA" + "TCG" + "AGT" + "AGC" + "ACT" + "ACC"
23           + "ACA" + "ACG" + "GTT" + "GTC" + "GTA" + "GTG" + "TGG" + "TAT"
24           + "TAC" + "TAA" + "TAG" + "TGA";
25
26   /**
27    * Test simple translation to Amino Acids (with STOP codons translated to X).
28    * 
29    * @throws IOException
30    */
31   @Test
32   public void testCdnaTranslate_simple() throws IOException
33   {
34     AlignmentI alf = new FormatAdapter().readFile(fasta,
35             FormatAdapter.PASTE, "FASTA");
36     final String sequenceAsString = alf
37                 .getSequenceAt(0).getSequenceAsString();
38     AlignmentI translated = Dna.cdnaTranslate(alf.getSequencesArray(),
39             new String[]
40             { sequenceAsString }, new int[]
41             { 0, alf.getWidth() - 1 }, alf.getGapCharacter(), null,
42             alf.getWidth(), null);
43     String aa = translated.getSequenceAt(0).getSequenceAsString();
44     assertEquals(
45             "AAAACCDDEEFFGGGGHHIIIKKLLLLLLMNNPPPPQQRRRRRRSSSSSSTTTTVVVVWYYXXX",
46             aa);
47   }
48
49   /**
50    * Test translation excluding hidden columns.
51    * 
52    * @throws IOException
53    */
54   @Test
55   public void testCdnaTranslate_hiddenColumns() throws IOException
56   {
57     AlignmentI alf = new FormatAdapter().readFile(fasta,
58             FormatAdapter.PASTE, "FASTA");
59     ColumnSelection cs = new jalview.datamodel.ColumnSelection();
60     cs.hideColumns(6, 14); // hide codons 3/4/5
61     cs.hideColumns(24, 35); // hide codons 9-12
62     cs.hideColumns(177, 191); // hide codons 60-64
63     AlignmentI translated = Dna.cdnaTranslate(alf.getSequencesArray(),
64             cs.getVisibleSequenceStrings(0, alf.getWidth(),
65                     alf.getSequencesArray()), new int[]
66             { 0, alf.getWidth() - 1 }, alf.getGapCharacter(), null,
67             alf.getWidth(), null);
68     String aa = translated.getSequenceAt(0).getSequenceAsString();
69     assertEquals("AACDDGGGGHHIIIKKLLLLLLMNNPPPPQQRRRRRRSSSSSSTTTTVVVVW", aa);
70   }
71
72   /**
73    * Tests for method that compares 'alignment' of two codon position triplets.
74    */
75   @Test
76   public void testCompareCodonPos()
77   {
78     /*
79      * Returns 0 for any null argument
80      */
81     assertEquals(0, Dna.compareCodonPos(new int[]
82       { 1, 2, 3 }, null));
83     assertEquals(0, Dna.compareCodonPos(null, new int[]
84       { 1, 2, 3 }));
85
86     /*
87      * Work through 27 combinations. First 9 cases where first position matches.
88      */
89     assertMatches("AAA", "GGG"); // 2 and 3 match
90     assertFollows("AA-A", "GGG"); // 2 matches, 3 shifted seq1
91     assertPrecedes("AAA", "GG-G"); // 2 matches, 3 shifted seq2
92     assertFollows("A-AA", "GG-G"); // 2 shifted seq1, 3 matches
93     assertFollows("A-A-A", "GG-G"); // 2 shifted seq1, 3 shifted seq1
94     // TODO is this right?
95     assertPrecedes("A-AA", "GG--G"); // 2 shifted seq1, 3 shifted seq2
96     assertPrecedes("AA-A", "G-GG"); // 2 shifted seq2, 3 matches
97     assertPrecedes("AA--A", "G-GG"); // 2 shifted seq2, 3 shifted seq1
98     assertPrecedes("AAA", "G-GG"); // 2 shifted seq2, 3 shifted seq2
99
100     /*
101      * 9 cases where first position is shifted in first sequence.
102      */
103     assertFollows("-AAA", "G-GG"); // 2 and 3 match
104     assertFollows("-AA-A", "G-GG"); // 2 matches, 3 shifted seq1
105     assertPrecedes("-AAA", "G-G-G"); // 2 matches, 3 shifted seq2
106     assertFollows("-A-AA", "G-G-G"); // 2 shifted seq1, 3 matches
107     assertFollows("-A-A-A", "G-G-G"); // 2 shifted seq1, 3 shifted seq1
108     // is this right? codon2 ends after codon1
109     assertPrecedes("-A-AA", "G-G--G"); // 2 shifted seq1, 3 shifted seq2
110     assertPrecedes("-AA-A", "G--GG"); // 2 shifted seq2, 3 matches
111     assertPrecedes("-AA--A", "G--GG"); // 2 shifted seq2, 3 shifted seq1
112     assertPrecedes("-AAA", "G--GG"); // 2 shifted seq2, 3 shifted seq2
113
114     /*
115      * 9 cases where first position is shifted in second sequence.
116      */
117     assertPrecedes("A-AA", "-GGG"); // 2 and 3 match
118     assertPrecedes("A-A-A", "-GGG"); // 2 matches, 3 shifted seq1
119     assertPrecedes("A-AA", "-GG-G"); // 2 matches, 3 shifted seq2
120     assertPrecedes("A--AA", "-GG-G"); // 2 shifted seq1, 3 matches
121     assertPrecedes("A--AA", "-GGG"); // 2 shifted seq1, 3 shifted seq1
122     assertPrecedes("A--AA", "-GG--G"); // 2 shifted seq1, 3 shifted seq2
123     assertPrecedes("AA-A", "-GGG"); // 2 shifted seq2, 3 matches
124     assertPrecedes("AA--A", "-GGG"); // 2 shifted seq2, 3 shifted seq1
125     assertPrecedes("AAA", "-GGG"); // 2 shifted seq2, 3 shifted seq2
126
127     /*
128      * two codon positions can each 'precede' the other! the comparison is
129      * biased to the first sequence
130      */
131     // TODO is this correct?
132     assertPrecedes("-A--AA", "--GGG");
133     assertPrecedes("--AAA", "-A--AA");
134   }
135
136   /**
137    * Assert that the first sequence should map to the same position as the
138    * second in a translated alignment
139    * 
140    * @param codon1
141    * @param codon2
142    */
143   private void assertMatches(String codon1, String codon2)
144   {
145     assertEquals("Expected match (0)", 0, compare(codon1, codon2));
146   }
147
148   /**
149    * Assert that the first sequence should precede the second in a translated
150    * alignment
151    * 
152    * @param codon1
153    * @param codon2
154    */
155   private void assertPrecedes(String codon1, String codon2)
156   {
157     assertEquals("Expected precedes (-1)", -1, compare(codon1, codon2));
158   }
159
160   /**
161    * Assert that the first sequence should follow the second in a translated
162    * alignment
163    * 
164    * @param codon1
165    * @param codon2
166    */
167   private void assertFollows(String codon1, String codon2)
168   {
169     assertEquals("Expected follows (1)", 1, compare(codon1, codon2));
170   }
171
172   /**
173    * Convert two nucleotide strings to base positions and pass to
174    * Dna.compareCodonPos, return the result.
175    * 
176    * @param s1
177    * @param s2
178    * @return
179    */
180   private int compare(String s1, String s2)
181   {
182     final int[] cd1 = convertCodon(s1);
183     final int[] cd2 = convertCodon(s2);
184     System.out.println("K: " + s1 + "  " + Arrays.toString(cd1));
185     System.out.println("G: " + s2 + "  " + Arrays.toString(cd2));
186     System.out.println();
187     return Dna.compareCodonPos(cd1, cd2);
188   }
189
190   /**
191    * Convert a string e.g. "-GC-T" to base positions e.g. [1, 2, 4]. The string
192    * should have exactly 3 non-gap characters, and use '-' for gaps.
193    * 
194    * @param s
195    * @return
196    */
197   private int[] convertCodon(String s)
198   {
199     int[] result = new int[3];
200     int i = 0;
201     for (int j = 0; j < s.length(); j++)
202     {
203       if (s.charAt(j) != '-')
204       {
205         result[i++] = j;
206       }
207     }
208     return result;
209   }
210
211   /**
212    * Weirdly, maybe worth a test to prove the helper method of this test class.
213    */
214   @Test
215   public void testConvertCodon()
216   {
217     assertEquals("[0, 1, 2]", Arrays.toString(convertCodon("AAA")));
218     assertEquals("[0, 2, 5]", Arrays.toString(convertCodon("A-A--A")));
219     assertEquals("[1, 3, 4]", Arrays.toString(convertCodon("-A-AA-")));
220   }
221 }