2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
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.
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.
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.
23 import static org.testng.AssertJUnit.assertEquals;
24 import static org.testng.AssertJUnit.assertNotNull;
25 import static org.testng.AssertJUnit.assertTrue;
26 import static org.testng.AssertJUnit.fail;
28 import jalview.datamodel.AlignmentAnnotation;
29 import jalview.datamodel.AlignmentI;
30 import jalview.datamodel.Annotation;
31 import jalview.datamodel.SequenceFeature;
32 import jalview.datamodel.SequenceI;
33 import jalview.gui.JvOptionPane;
36 import java.util.BitSet;
37 import java.util.HashMap;
40 import org.testng.annotations.BeforeClass;
41 import org.testng.annotations.Test;
43 public class StockholmFileTest
46 @BeforeClass(alwaysRun = true)
47 public void setUpJvOptionPane()
49 JvOptionPane.setInteractiveMode(false);
50 JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
53 static String PfamFile = "examples/PF00111_seed.stk",
54 RfamFile = "examples/RF00031_folded.stk";
56 @Test(groups = { "Functional" })
57 public void pfamFileIO() throws Exception
59 testFileIOwithFormat(new File(PfamFile), FileFormat.Stockholm, -1, 0,
63 @Test(groups = { "Functional" })
64 public void pfamFileDataExtraction() throws Exception
66 AppletFormatAdapter af = new AppletFormatAdapter();
67 AlignmentI al = af.readFile(PfamFile, DataSourceType.FILE,
68 new IdentifyFile().identify(PfamFile, DataSourceType.FILE));
70 for (SequenceI sq : al.getSequences())
72 if (sq.getAllPDBEntries() != null)
74 numpdb += sq.getAllPDBEntries().size();
78 "PF00111 seed alignment has at least 1 PDB file, but the reader found none.",
82 @Test(groups = { "Functional" })
83 public void rfamFileIO() throws Exception
85 testFileIOwithFormat(new File(RfamFile), FileFormat.Stockholm, 2, 1,
90 * test alignment data in given file can be imported, exported and reimported
94 * - source datafile (IdentifyFile.identify() should work with it)
96 * - label for IO class used to write and read back in the data from
98 * @param ignoreRowVisibility
101 public static void testFileIOwithFormat(File f, FileFormatI ioformat,
102 int naliannot, int nminseqann, boolean ignoreRowVisibility)
104 System.out.println("Reading file: " + f);
105 String ff = f.getPath();
108 AppletFormatAdapter rf = new AppletFormatAdapter();
110 AlignmentI al = rf.readFile(ff, DataSourceType.FILE,
111 new IdentifyFile().identify(ff, DataSourceType.FILE));
113 assertNotNull("Couldn't read supplied alignment data.", al);
115 // make sure dataset is initialised ? not sure about this
116 for (int i = 0; i < al.getSequencesArray().length; ++i)
118 al.getSequenceAt(i).createDatasetSequence();
120 String outputfile = rf.formatSequences(ioformat, al, true);
121 System.out.println("Output file in '" + ioformat + "':\n"
122 + outputfile + "\n<<EOF\n");
123 // test for consistency in io
124 AlignmentI al_input = new AppletFormatAdapter().readFile(outputfile,
125 DataSourceType.PASTE, ioformat);
126 assertNotNull("Couldn't parse reimported alignment data.", al_input);
128 FileFormatI identifyoutput = new IdentifyFile().identify(outputfile,
129 DataSourceType.PASTE);
130 assertNotNull("Identify routine failed for outputformat " + ioformat,
133 "Identify routine could not recognise output generated by '"
134 + ioformat + "' writer",
135 ioformat.equals(identifyoutput));
136 testAlignmentEquivalence(al, al_input, false);
137 int numaliannot = 0, numsqswithali = 0;
138 for (AlignmentAnnotation ala : al_input.getAlignmentAnnotation())
140 if (ala.sequenceRef == null)
151 assertEquals("Number of alignment annotations", naliannot,
156 "Number of sequence associated annotations wasn't at least "
157 + nminseqann, numsqswithali >= nminseqann);
159 } catch (Exception e)
162 assertTrue("Couln't format the alignment for output file.", false);
167 * assert alignment equivalence
172 * 'secondary' or generated alignment from some datapreserving
174 * @param ignoreFeatures
175 * when true, differences in sequence feature annotation are ignored
177 public static void testAlignmentEquivalence(AlignmentI al,
178 AlignmentI al_input, boolean ignoreFeatures)
183 * assert alignment equivalence
188 * 'secondary' or generated alignment from some datapreserving
190 * @param ignoreFeatures
191 * when true, differences in sequence feature annotation are ignored
193 * @param ignoreRowVisibility
194 * when true, do not fail if there are differences in the visibility
197 public static void testAlignmentEquivalence(AlignmentI al,
198 AlignmentI al_input, boolean ignoreFeatures,
199 boolean ignoreRowVisibility)
201 assertNotNull("Original alignment was null", al);
202 assertNotNull("Generated alignment was null", al_input);
204 assertTrue("Alignment dimension mismatch: original: " + al.getHeight()
205 + "x" + al.getWidth() + ", generated: " + al_input.getHeight()
206 + "x" + al_input.getWidth(),
207 al.getHeight() == al_input.getHeight()
208 && al.getWidth() == al_input.getWidth());
210 // check Alignment annotation
211 AlignmentAnnotation[] aa_new = al_input.getAlignmentAnnotation();
212 AlignmentAnnotation[] aa_original = al.getAlignmentAnnotation();
214 // note - at moment we do not distinguish between alignment without any
215 // annotation rows and alignment with no annotation row vector
216 // we might want to revise this in future
217 int aa_new_size = (aa_new == null ? 0 : aa_new.length);
218 int aa_original_size = (aa_original == null ? 0 : aa_original.length);
219 Map<Integer, BitSet> orig_groups = new HashMap<Integer, BitSet>();
220 Map<Integer, BitSet> new_groups = new HashMap<Integer, BitSet>();
222 if (aa_new != null && aa_original != null)
224 for (int i = 0; i < aa_original.length; i++)
226 if (aa_new.length > i)
228 assertEqualSecondaryStructure(
229 "Different alignment annotation at position " + i,
230 aa_original[i], aa_new[i]);
231 // compare graphGroup or graph properties - needed to verify JAL-1299
232 assertEquals("Graph type not identical.", aa_original[i].graph,
234 if (!ignoreRowVisibility)
236 assertEquals("Visibility not identical.",
237 aa_original[i].visible,
240 assertEquals("Threshold line not identical.",
241 aa_original[i].threshold, aa_new[i].threshold);
242 // graphGroup may differ, but pattern should be the same
243 Integer o_ggrp = new Integer(aa_original[i].graphGroup + 2);
244 Integer n_ggrp = new Integer(aa_new[i].graphGroup + 2);
245 BitSet orig_g = orig_groups.get(o_ggrp);
246 BitSet new_g = new_groups.get(n_ggrp);
249 orig_groups.put(o_ggrp, orig_g = new BitSet());
253 new_groups.put(n_ggrp, new_g = new BitSet());
255 assertEquals("Graph Group pattern differs at annotation " + i,
262 System.err.println("No matching annotation row for "
263 + aa_original[i].toString());
268 "Generated and imported alignment have different annotation sets",
269 aa_original_size, aa_new_size);
271 // check sequences, annotation and features
272 SequenceI[] seq_original = new SequenceI[al.getSequencesArray().length];
273 seq_original = al.getSequencesArray();
274 SequenceI[] seq_new = new SequenceI[al_input.getSequencesArray().length];
275 seq_new = al_input.getSequencesArray();
276 SequenceFeature[] sequenceFeatures_original, sequenceFeatures_new;
277 AlignmentAnnotation annot_original, annot_new;
279 for (int i = 0; i < al.getSequencesArray().length; i++)
281 String name = seq_original[i].getName();
282 int start = seq_original[i].getStart();
283 int end = seq_original[i].getEnd();
284 System.out.println("Check sequence: " + name + "/" + start + "-"
287 // search equal sequence
288 for (int in = 0; in < al_input.getSequencesArray().length; in++)
290 if (name.equals(seq_new[in].getName())
291 && start == seq_new[in].getStart()
292 && end == seq_new[in].getEnd())
294 String ss_original = seq_original[i].getSequenceAsString();
295 String ss_new = seq_new[in].getSequenceAsString();
296 assertEquals("The sequences " + name + "/" + start + "-" + end
297 + " are not equal", ss_original, ss_new);
300 "Sequence Features were not equivalent"
301 + (ignoreFeatures ? " ignoring." : ""),
303 || (seq_original[i].getSequenceFeatures() == null && seq_new[in]
304 .getSequenceFeatures() == null)
305 || (seq_original[i].getSequenceFeatures() != null && seq_new[in]
306 .getSequenceFeatures() != null));
307 // compare sequence features
308 if (seq_original[i].getSequenceFeatures() != null
309 && seq_new[in].getSequenceFeatures() != null)
311 System.out.println("There are feature!!!");
312 sequenceFeatures_original = new SequenceFeature[seq_original[i]
313 .getSequenceFeatures().length];
314 sequenceFeatures_original = seq_original[i]
315 .getSequenceFeatures();
316 sequenceFeatures_new = new SequenceFeature[seq_new[in]
317 .getSequenceFeatures().length];
318 sequenceFeatures_new = seq_new[in].getSequenceFeatures();
320 assertEquals("different number of features",
321 seq_original[i].getSequenceFeatures().length,
322 seq_new[in].getSequenceFeatures().length);
324 for (int feat = 0; feat < seq_original[i].getSequenceFeatures().length; feat++)
326 assertEquals("Different features",
327 sequenceFeatures_original[feat],
328 sequenceFeatures_new[feat]);
331 // compare alignment annotation
332 if (al.getSequenceAt(i).getAnnotation() != null
333 && al_input.getSequenceAt(in).getAnnotation() != null)
335 for (int j = 0; j < al.getSequenceAt(i).getAnnotation().length; j++)
337 if (al.getSequenceAt(i).getAnnotation()[j] != null
338 && al_input.getSequenceAt(in).getAnnotation()[j] != null)
340 annot_original = al.getSequenceAt(i).getAnnotation()[j];
341 annot_new = al_input.getSequenceAt(in).getAnnotation()[j];
342 assertEqualSecondaryStructure(
343 "Different annotation elements", annot_original,
348 else if (al.getSequenceAt(i).getAnnotation() == null
349 && al_input.getSequenceAt(in).getAnnotation() == null)
351 System.out.println("No annotations");
353 else if (al.getSequenceAt(i).getAnnotation() != null
354 && al_input.getSequenceAt(in).getAnnotation() == null)
356 fail("Annotations differed between sequences ("
357 + al.getSequenceAt(i).getName() + ") and ("
358 + al_input.getSequenceAt(i).getName() + ")");
366 private static void assertEqualSecondaryStructure(String message,
367 AlignmentAnnotation annot_or,
368 AlignmentAnnotation annot_new)
370 // TODO: test to cover this assert behaves correctly for all allowed
371 // variations of secondary structure annotation row equivalence
372 if (annot_or.annotations.length != annot_new.annotations.length)
374 fail("Different lengths for annotation row elements: "
375 + annot_or.annotations.length + "!="
376 + annot_new.annotations.length);
378 boolean isRna = annot_or.isRNA();
379 assertTrue("Expected " + (isRna ? " valid RNA " : " no RNA ")
380 + " secondary structure in the row.",
381 isRna == annot_new.isRNA());
382 for (int i = 0; i < annot_or.annotations.length; i++)
384 Annotation an_or = annot_or.annotations[i], an_new = annot_new.annotations[i];
385 if (an_or != null && an_new != null)
390 if (an_or.secondaryStructure != an_new.secondaryStructure
391 || an_or.value != an_new.value)
393 fail("Different RNA secondary structure at column " + i
394 + " expected: [" + annot_or.annotations[i].toString()
395 + "] but got: [" + annot_new.annotations[i].toString()
401 // not RNA secondary structure, so expect all elements to match...
402 if (!an_or.displayCharacter.trim().equals(
403 an_new.displayCharacter.trim())
404 || !("" + an_or.secondaryStructure).trim().equals(
405 ("" + an_new.secondaryStructure).trim())
406 || (an_or.description != an_new.description && !((an_or.description == null && an_new.description
407 .trim().length() == 0)
408 || (an_new.description == null && an_or.description
409 .trim().length() == 0) || an_or.description
410 .trim().equals(an_new.description.trim()))))
412 fail("Annotation Element Mismatch\nElement " + i
413 + " in original: " + annot_or.annotations[i].toString()
414 + "\nElement " + i + " in new: "
415 + annot_new.annotations[i].toString());
419 else if (annot_or.annotations[i] == null
420 && annot_new.annotations[i] == null)
426 fail("Annotation Element Mismatch\nElement "
429 + (annot_or.annotations[i] == null ? "is null"
430 : annot_or.annotations[i].toString())
434 + (annot_new.annotations[i] == null ? "is null"
435 : annot_new.annotations[i].toString()));
440 String aliFile = ">Dm\nAAACCCUUUUACACACGGGAAAGGG";
441 String annFile = "JALVIEW_ANNOTATION\n# Created: Thu May 04 11:16:52 BST 2017\n\n"
442 + "SEQUENCE_REF\tDm\nNO_GRAPH\tsecondary structure\tsecondary structure\t"
443 + "(|(|(|(|, .|, .|, .|, .|)|)|)|)|\t0.0\nROWPROPERTIES\t"
444 + "secondary structure\tscaletofit=true\tshowalllabs=true\tcentrelabs=false";
446 @Test(groups = { "Functional" })
447 public void secondaryStructureForRNASequence() throws Exception
449 AlignmentI al = new AppletFormatAdapter().readFile(aliFile,
450 DataSourceType.PASTE, jalview.io.FileFormat.Fasta);
451 AnnotationFile aaf = new AnnotationFile();
452 aaf.readAnnotationFile(al, annFile, DataSourceType.PASTE);
453 al.getAlignmentAnnotation()[0].visible = true;
455 // TODO: create a better 'save as <format>' pattern
456 StockholmFile sf = new StockholmFile(al);
458 String stockholmFile = sf.print(al.getSequencesArray(), true);
460 AlignmentI newAl = new AppletFormatAdapter().readFile(stockholmFile,
461 DataSourceType.PASTE, jalview.io.FileFormat.Stockholm);
462 // AlignmentUtils.showOrHideSequenceAnnotations(newAl.getViewport()
463 // .getAlignment(), Arrays.asList("Secondary Structure"), newAl
464 // .getViewport().getAlignment().getSequences(), true, true);
465 testAlignmentEquivalence(al, newAl, true, true);