/* * 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; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertNotNull; import static org.testng.AssertJUnit.assertTrue; import static org.testng.AssertJUnit.fail; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.Annotation; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; import jalview.gui.JvOptionPane; import java.io.File; import java.util.BitSet; import java.util.HashMap; import java.util.Map; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class StockholmFileTest { @BeforeClass(alwaysRun = true) public void setUpJvOptionPane() { JvOptionPane.setInteractiveMode(false); JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION); } static String PfamFile = "examples/PF00111_seed.stk", RfamFile = "examples/RF00031_folded.stk"; @Test(groups = { "Functional" }) public void pfamFileIO() throws Exception { testFileIOwithFormat(new File(PfamFile), FileFormat.Stockholm, -1, 0, false); } @Test(groups = { "Functional" }) public void pfamFileDataExtraction() throws Exception { AppletFormatAdapter af = new AppletFormatAdapter(); AlignmentI al = af.readFile(PfamFile, DataSourceType.FILE, new IdentifyFile().identify(PfamFile, DataSourceType.FILE)); int numpdb = 0; for (SequenceI sq : al.getSequences()) { if (sq.getAllPDBEntries() != null) { numpdb += sq.getAllPDBEntries().size(); } } assertTrue( "PF00111 seed alignment has at least 1 PDB file, but the reader found none.", numpdb > 0); } @Test(groups = { "Functional" }) public void rfamFileIO() throws Exception { testFileIOwithFormat(new File(RfamFile), FileFormat.Stockholm, 2, 1, false); } /** * test alignment data in given file can be imported, exported and reimported * with no dataloss * * @param f * - source datafile (IdentifyFile.identify() should work with it) * @param ioformat * - label for IO class used to write and read back in the data from * f * @param ignoreRowVisibility */ public static void testFileIOwithFormat(File f, FileFormatI ioformat, int naliannot, int nminseqann, boolean ignoreRowVisibility) { System.out.println("Reading file: " + f); String ff = f.getPath(); try { AppletFormatAdapter rf = new AppletFormatAdapter(); AlignmentI al = rf.readFile(ff, DataSourceType.FILE, new IdentifyFile().identify(ff, DataSourceType.FILE)); assertNotNull("Couldn't read supplied alignment data.", al); // make sure dataset is initialised ? not sure about this for (int i = 0; i < al.getSequencesArray().length; ++i) { al.getSequenceAt(i).createDatasetSequence(); } String outputfile = rf.formatSequences(ioformat, al, true); System.out.println("Output file in '" + ioformat + "':\n" + outputfile + "\n< -1) { assertEquals("Number of alignment annotations", naliannot, numaliannot); } assertTrue( "Number of sequence associated annotations wasn't at least " + nminseqann, numsqswithali >= nminseqann); } catch (Exception e) { e.printStackTrace(); assertTrue("Couln't format the alignment for output file.", false); } } /** * assert alignment equivalence * * @param al * 'original' * @param al_input * 'secondary' or generated alignment from some datapreserving * transformation * @param ignoreFeatures * when true, differences in sequence feature annotation are ignored */ public static void testAlignmentEquivalence(AlignmentI al, AlignmentI al_input, boolean ignoreFeatures) { } /** * assert alignment equivalence * * @param al * 'original' * @param al_input * 'secondary' or generated alignment from some datapreserving * transformation * @param ignoreFeatures * when true, differences in sequence feature annotation are ignored * * @param ignoreRowVisibility * when true, do not fail if there are differences in the visibility * of annotation rows */ public static void testAlignmentEquivalence(AlignmentI al, AlignmentI al_input, boolean ignoreFeatures, boolean ignoreRowVisibility) { assertNotNull("Original alignment was null", al); assertNotNull("Generated alignment was null", al_input); assertTrue("Alignment dimension mismatch: original: " + al.getHeight() + "x" + al.getWidth() + ", generated: " + al_input.getHeight() + "x" + al_input.getWidth(), al.getHeight() == al_input.getHeight() && al.getWidth() == al_input.getWidth()); // check Alignment annotation AlignmentAnnotation[] aa_new = al_input.getAlignmentAnnotation(); AlignmentAnnotation[] aa_original = al.getAlignmentAnnotation(); // note - at moment we do not distinguish between alignment without any // annotation rows and alignment with no annotation row vector // we might want to revise this in future int aa_new_size = (aa_new == null ? 0 : aa_new.length); int aa_original_size = (aa_original == null ? 0 : aa_original.length); Map orig_groups = new HashMap(); Map new_groups = new HashMap(); if (aa_new != null && aa_original != null) { for (int i = 0; i < aa_original.length; i++) { if (aa_new.length > i) { assertEqualSecondaryStructure( "Different alignment annotation at position " + i, aa_original[i], aa_new[i]); // compare graphGroup or graph properties - needed to verify JAL-1299 assertEquals("Graph type not identical.", aa_original[i].graph, aa_new[i].graph); if (!ignoreRowVisibility) { assertEquals("Visibility not identical.", aa_original[i].visible, aa_new[i].visible); } assertEquals("Threshold line not identical.", aa_original[i].threshold, aa_new[i].threshold); // graphGroup may differ, but pattern should be the same Integer o_ggrp = new Integer(aa_original[i].graphGroup + 2); Integer n_ggrp = new Integer(aa_new[i].graphGroup + 2); BitSet orig_g = orig_groups.get(o_ggrp); BitSet new_g = new_groups.get(n_ggrp); if (orig_g == null) { orig_groups.put(o_ggrp, orig_g = new BitSet()); } if (new_g == null) { new_groups.put(n_ggrp, new_g = new BitSet()); } assertEquals("Graph Group pattern differs at annotation " + i, orig_g, new_g); orig_g.set(i); new_g.set(i); } else { System.err.println("No matching annotation row for " + aa_original[i].toString()); } } } assertEquals( "Generated and imported alignment have different annotation sets", aa_original_size, aa_new_size); // check sequences, annotation and features SequenceI[] seq_original = new SequenceI[al.getSequencesArray().length]; seq_original = al.getSequencesArray(); SequenceI[] seq_new = new SequenceI[al_input.getSequencesArray().length]; seq_new = al_input.getSequencesArray(); SequenceFeature[] sequenceFeatures_original, sequenceFeatures_new; AlignmentAnnotation annot_original, annot_new; // for (int i = 0; i < al.getSequencesArray().length; i++) { String name = seq_original[i].getName(); int start = seq_original[i].getStart(); int end = seq_original[i].getEnd(); System.out.println("Check sequence: " + name + "/" + start + "-" + end); // search equal sequence for (int in = 0; in < al_input.getSequencesArray().length; in++) { if (name.equals(seq_new[in].getName()) && start == seq_new[in].getStart() && end == seq_new[in].getEnd()) { String ss_original = seq_original[i].getSequenceAsString(); String ss_new = seq_new[in].getSequenceAsString(); assertEquals("The sequences " + name + "/" + start + "-" + end + " are not equal", ss_original, ss_new); assertTrue( "Sequence Features were not equivalent" + (ignoreFeatures ? " ignoring." : ""), ignoreFeatures || (seq_original[i].getSequenceFeatures() == null && seq_new[in] .getSequenceFeatures() == null) || (seq_original[i].getSequenceFeatures() != null && seq_new[in] .getSequenceFeatures() != null)); // compare sequence features if (seq_original[i].getSequenceFeatures() != null && seq_new[in].getSequenceFeatures() != null) { System.out.println("There are feature!!!"); sequenceFeatures_original = new SequenceFeature[seq_original[i] .getSequenceFeatures().length]; sequenceFeatures_original = seq_original[i] .getSequenceFeatures(); sequenceFeatures_new = new SequenceFeature[seq_new[in] .getSequenceFeatures().length]; sequenceFeatures_new = seq_new[in].getSequenceFeatures(); assertEquals("different number of features", seq_original[i].getSequenceFeatures().length, seq_new[in].getSequenceFeatures().length); for (int feat = 0; feat < seq_original[i].getSequenceFeatures().length; feat++) { assertEquals("Different features", sequenceFeatures_original[feat], sequenceFeatures_new[feat]); } } // compare alignment annotation if (al.getSequenceAt(i).getAnnotation() != null && al_input.getSequenceAt(in).getAnnotation() != null) { for (int j = 0; j < al.getSequenceAt(i).getAnnotation().length; j++) { if (al.getSequenceAt(i).getAnnotation()[j] != null && al_input.getSequenceAt(in).getAnnotation()[j] != null) { annot_original = al.getSequenceAt(i).getAnnotation()[j]; annot_new = al_input.getSequenceAt(in).getAnnotation()[j]; assertEqualSecondaryStructure( "Different annotation elements", annot_original, annot_new); } } } else if (al.getSequenceAt(i).getAnnotation() == null && al_input.getSequenceAt(in).getAnnotation() == null) { System.out.println("No annotations"); } else if (al.getSequenceAt(i).getAnnotation() != null && al_input.getSequenceAt(in).getAnnotation() == null) { fail("Annotations differed between sequences (" + al.getSequenceAt(i).getName() + ") and (" + al_input.getSequenceAt(i).getName() + ")"); } break; } } } } private static void assertEqualSecondaryStructure(String message, AlignmentAnnotation annot_or, AlignmentAnnotation annot_new) { // TODO: test to cover this assert behaves correctly for all allowed // variations of secondary structure annotation row equivalence if (annot_or.annotations.length != annot_new.annotations.length) { fail("Different lengths for annotation row elements: " + annot_or.annotations.length + "!=" + annot_new.annotations.length); } boolean isRna = annot_or.isRNA(); assertTrue("Expected " + (isRna ? " valid RNA " : " no RNA ") + " secondary structure in the row.", isRna == annot_new.isRNA()); for (int i = 0; i < annot_or.annotations.length; i++) { Annotation an_or = annot_or.annotations[i], an_new = annot_new.annotations[i]; if (an_or != null && an_new != null) { if (isRna) { if (an_or.secondaryStructure != an_new.secondaryStructure || an_or.value != an_new.value) { fail("Different RNA secondary structure at column " + i + " expected: [" + annot_or.annotations[i].toString() + "] but got: [" + annot_new.annotations[i].toString() + "]"); } } else { // not RNA secondary structure, so expect all elements to match... if (!an_or.displayCharacter.trim().equals( an_new.displayCharacter.trim()) || !("" + an_or.secondaryStructure).trim().equals( ("" + an_new.secondaryStructure).trim()) || (an_or.description != an_new.description && !((an_or.description == null && an_new.description .trim().length() == 0) || (an_new.description == null && an_or.description .trim().length() == 0) || an_or.description .trim().equals(an_new.description.trim())))) { fail("Annotation Element Mismatch\nElement " + i + " in original: " + annot_or.annotations[i].toString() + "\nElement " + i + " in new: " + annot_new.annotations[i].toString()); } } } else if (annot_or.annotations[i] == null && annot_new.annotations[i] == null) { continue; } else { fail("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())); } } } }