JAL-1297 JAL-1295 JAL-1294 improve test logic for comparing annotation elements
[jalview.git] / test / jalview / io / StockholmFileTest.java
1 package jalview.io;
2
3 import static org.junit.Assert.*;
4 import jalview.datamodel.Alignment;
5 import jalview.datamodel.AlignmentAnnotation;
6 import jalview.datamodel.AlignmentI;
7 import jalview.datamodel.Annotation;
8 import jalview.datamodel.SequenceFeature;
9 import jalview.datamodel.SequenceI;
10
11 import java.io.File;
12 import java.io.IOException;
13 import java.io.InputStream;
14
15 import org.junit.Test;
16
17 public class StockholmFileTest
18 {
19
20   static String PfamFile = "examples/PF00111_seed.stk",
21           RfamFile = "examples/RF00031_folded.stk";
22
23   @Test
24   public void pfamFileIO() throws Exception
25   {
26     testFileIOwithFormat(new File(PfamFile), "STH");
27   }
28   @Test
29   public void pfamFileDataExtraction() throws Exception
30   {  AppletFormatAdapter af = new AppletFormatAdapter();
31     AlignmentI al = af.readFile(PfamFile, af.FILE,
32             new IdentifyFile().Identify(PfamFile, af.FILE));
33     int numpdb = 0;
34     for (SequenceI sq : al.getSequences())
35     {
36       if (sq.getPDBId() != null)
37       {
38         numpdb += sq.getPDBId().size();
39       }
40     }
41     assertTrue(
42             "PF00111 seed alignment has at least 1 PDB file, but the reader found none.",
43             numpdb > 0);
44   }
45
46   @Test
47   public void rfamFileIO() throws Exception
48   {
49     testFileIOwithFormat(new File(RfamFile), "STH");
50   }
51
52   /**
53    * test alignment data in given file can be imported, exported and reimported
54    * with no dataloss
55    * 
56    * @param f
57    *          - source datafile (IdentifyFile.identify() should work with it)
58    * @param ioformat
59    *          - label for IO class used to write and read back in the data from
60    *          f
61    */
62   public static void testFileIOwithFormat(File f, String ioformat)
63   {
64     System.out.println("Reading file: " + f);
65     String ff = f.getPath();
66     try
67     {
68       AppletFormatAdapter rf = new AppletFormatAdapter();
69
70       Alignment al = rf.readFile(ff, AppletFormatAdapter.FILE,
71               new IdentifyFile().Identify(ff, AppletFormatAdapter.FILE));
72
73       assertNotNull("Couldn't read supplied alignment data.", al);
74
75       // make sure dataset is initialised ? not sure about this
76       for (int i = 0; i < al.getSequencesArray().length; ++i)
77       {
78         al.getSequenceAt(i).setDatasetSequence(al.getSequenceAt(i));
79       }
80       String outputfile = rf.formatSequences(ioformat, al, true);
81       System.out.println("Output file in '"+ioformat+"':\n"+outputfile+"\n<<EOF\n");
82       // test for consistency in io
83       Alignment al_input = new AppletFormatAdapter().readFile(outputfile,
84               AppletFormatAdapter.PASTE, ioformat);
85       assertNotNull("Couldn't parse reimported alignment data.", al_input);
86
87       String identifyoutput = new IdentifyFile().Identify(outputfile,
88               AppletFormatAdapter.PASTE);
89       assertNotNull("Identify routine failed for outputformat " + ioformat,
90               identifyoutput);
91       assertTrue(
92               "Identify routine could not recognise output generated by '"
93                       + ioformat + "' writer",
94               ioformat.equals(identifyoutput));
95       testAlignmentEquivalence(al, al_input);
96     } catch (Exception e)
97     {
98       e.printStackTrace();
99       assertTrue("Couln't format the alignment for output file.", false);
100     }
101   }
102
103   /**
104    * assert alignment equivalence
105    * 
106    * @param al
107    *          'original'
108    * @param al_input
109    *          'secondary' or generated alignment from some datapreserving
110    *          transformation
111    */
112   private static void testAlignmentEquivalence(AlignmentI al,
113           AlignmentI al_input)
114   {
115     assertNotNull("Original alignment was null", al);
116     assertNotNull("Generated alignment was null", al_input);
117
118     assertTrue(
119             "Alignment dimension mismatch: originl contains "
120                     + al.getHeight() + " and generated has "
121                     + al_input.getHeight() + " sequences; original has "
122                     + al.getWidth() + " and generated has "
123                     + al_input.getWidth() + " columns.",
124             al.getHeight() == al_input.getHeight()
125                     && al.getWidth() == al_input.getWidth());
126
127     // check Alignment annotation
128     AlignmentAnnotation[] aa_new = al_input.getAlignmentAnnotation();
129     AlignmentAnnotation[] aa_original = al.getAlignmentAnnotation();
130
131     // note - at moment we do not distinguish between alignment without any
132     // annotation rows and alignment with no annotation row vector
133     // we might want to revise this in future
134     int aa_new_size = (aa_new == null ? 0 : aa_new.length), aa_original_size = (aa_original == null ? 0
135             : aa_original.length);
136
137     if (aa_new != null && aa_original != null)
138     {
139       for (int i = 0; i < aa_original.length; i++)
140       {
141         if (aa_new.length>i) {
142           assertTrue("Different alignment annotation at position "+i,
143                 equalss(aa_original[i], aa_new[i]));
144         } else {
145           System.err.println("No matching annotation row for "+aa_original[i].toString());
146         }
147       }
148     }
149     assertTrue(
150             "Generated and imported alignment have different annotation sets ("
151                     + aa_new_size + " != " + aa_original_size + ")",
152             aa_new_size == aa_original_size);
153
154     // check sequences, annotation and features
155     SequenceI[] seq_original = new SequenceI[al.getSequencesArray().length];
156     seq_original = al.getSequencesArray();
157     SequenceI[] seq_new = new SequenceI[al_input.getSequencesArray().length];
158     seq_new = al_input.getSequencesArray();
159     SequenceFeature[] sequenceFeatures_original, sequenceFeatures_new;
160     AlignmentAnnotation annot_original, annot_new;
161     //
162     for (int i = 0; i < al.getSequencesArray().length; i++)
163     {
164       String name = seq_original[i].getName();
165       int start = seq_original[i].getStart();
166       int end = seq_original[i].getEnd();
167       System.out.println("Check sequence: " + name + "/" + start + "-"
168               + end);
169
170       // search equal sequence
171       for (int in = 0; in < al_input.getSequencesArray().length; in++)
172       {
173         if (name.equals(seq_new[in].getName())
174                 && start == seq_new[in].getStart()
175                 && end == seq_new[in].getEnd())
176         {
177           String ss_original = seq_original[i].getSequenceAsString();
178           String ss_new = seq_new[in].getSequenceAsString();
179           assertTrue("The sequences " + name + "/" + start + "-" + end
180                   + " are not equal", ss_original.equals(ss_new));
181
182           assertTrue(
183                   "Sequence Features were not equivalent",
184                   (seq_original[i].getSequenceFeatures() == null && seq_new[in]
185                           .getSequenceFeatures() == null)
186                           || (seq_original[i].getSequenceFeatures() != null && seq_new[in]
187                                   .getSequenceFeatures() != null));
188           // compare sequence features
189           if (seq_original[i].getSequenceFeatures() != null
190                   && seq_new[in].getSequenceFeatures() != null)
191           {
192             System.out.println("There are feature!!!");
193             sequenceFeatures_original = new SequenceFeature[seq_original[i]
194                     .getSequenceFeatures().length];
195             sequenceFeatures_original = seq_original[i]
196                     .getSequenceFeatures();
197             sequenceFeatures_new = new SequenceFeature[seq_new[in]
198                     .getSequenceFeatures().length];
199             sequenceFeatures_new = seq_new[in].getSequenceFeatures();
200
201             assertTrue("different number of features", seq_original[i]
202                     .getSequenceFeatures().length == seq_new[in]
203                     .getSequenceFeatures().length);
204
205             for (int feat = 0; feat < seq_original[i].getSequenceFeatures().length; feat++)
206             {
207               assertTrue("Different features",
208                       sequenceFeatures_original[feat]
209                               .equals(sequenceFeatures_new[feat]));
210             }
211           }
212
213           // compare alignment annotation
214           if (al.getSequenceAt(i).getAnnotation() != null
215                   && al_input.getSequenceAt(in).getAnnotation() != null)
216           {
217             for (int j = 0; j < al.getSequenceAt(i).getAnnotation().length; j++)
218             {
219               if (al.getSequenceAt(i).getAnnotation()[j] != null
220                       && al_input.getSequenceAt(in).getAnnotation()[j] != null)
221               {
222                 annot_original = al.getSequenceAt(i).getAnnotation()[j];
223                 annot_new = al_input.getSequenceAt(in).getAnnotation()[j];
224                 assertTrue("Different annotation",
225                         equalss(annot_original, annot_new));
226               }
227             }
228           }
229           else if (al.getSequenceAt(i).getAnnotation() == null
230                   && al_input.getSequenceAt(in).getAnnotation() == null)
231           {
232             System.out.println("No annotations");
233           }
234           else if (al.getSequenceAt(i).getAnnotation() != null
235                   && al_input.getSequenceAt(in).getAnnotation() == null)
236           {
237             assertTrue("Annotations differed between sequences ("
238                     + al.getSequenceAt(i).getName() + ") and ("
239                     + al_input.getSequenceAt(i).getName() + ")", false);
240           }
241           break;
242         }
243       }
244     }
245   }
246
247   /*
248    * compare annotations
249    */
250   private static boolean equalss(AlignmentAnnotation annot_or,
251           AlignmentAnnotation annot_new)
252   {
253     if (annot_or.annotations.length != annot_new.annotations.length)
254     {
255       System.err.println("Different lengths for annotation row elements: "+annot_or.annotations.length +"!="+ annot_new.annotations.length);
256       return false;
257     }
258     // TODO: does not compare graphGroup or graph properties
259     // TODO: does not compare visibility
260     for (int i = 0; i < annot_or.annotations.length; i++)
261     {
262       Annotation an_or=annot_or.annotations[i],an_new=annot_new.annotations[i];
263       if (an_or != null
264               && an_new!= null)
265       {
266         if (!an_or.displayCharacter
267                 .equals(an_new.displayCharacter)
268                 || an_or.secondaryStructure != an_new.secondaryStructure
269                 || (an_or.description != an_new.description && (an_or.description == null
270                         || an_new.description == null || !an_or.description
271                           .equals(an_new.description))))
272         {
273           System.err.println("Annotation Element Mismatch\nElement "+i+" in original: "+annot_or.annotations[i].toString()+"\nElement "+i+" in new: "+annot_new.annotations[i].toString());
274           return false;
275         }
276       }
277       else if (annot_or.annotations[i] == null
278               && annot_new.annotations[i] == null)
279       {
280         continue;
281       }
282       else
283       {
284         System.err.println("Annotation Element Mismatch\nElement "+i+" in original: "+(annot_or.annotations[i]==null ? "is null" : annot_or.annotations[i].toString())+"\nElement "+i+" in new: "+(annot_new.annotations[i] == null ? "is null" : annot_new.annotations[i].toString()));
285         return false;
286       }
287     }
288     return true;
289   }
290 }