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.assertFalse;
25 import static org.testng.AssertJUnit.assertNotNull;
26 import static org.testng.AssertJUnit.assertTrue;
28 import jalview.api.FeatureColourI;
29 import jalview.api.FeatureRenderer;
30 import jalview.datamodel.Alignment;
31 import jalview.datamodel.AlignmentI;
32 import jalview.datamodel.SequenceDummy;
33 import jalview.datamodel.SequenceFeature;
34 import jalview.datamodel.SequenceI;
35 import jalview.datamodel.features.SequenceFeatures;
36 import jalview.gui.AlignFrame;
37 import jalview.gui.JvOptionPane;
39 import java.awt.Color;
41 import java.io.IOException;
42 import java.util.ArrayList;
43 import java.util.Arrays;
44 import java.util.HashMap;
45 import java.util.List;
48 import org.testng.annotations.BeforeClass;
49 import org.testng.annotations.Test;
51 public class FeaturesFileTest
54 @BeforeClass(alwaysRun = true)
55 public void setUpJvOptionPane()
57 JvOptionPane.setInteractiveMode(false);
58 JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
61 private static String simpleGffFile = "examples/testdata/simpleGff3.gff";
63 @Test(groups = { "Functional" })
64 public void testParse() throws Exception
66 File f = new File("examples/uniref50.fa");
67 AlignmentI al = readAlignmentFile(f);
68 AlignFrame af = new AlignFrame(al, 500, 500);
69 Map<String, FeatureColourI> colours = af.getFeatureRenderer()
71 FeaturesFile featuresFile = new FeaturesFile(
72 "examples/exampleFeatures.txt", DataSourceType.FILE);
73 assertTrue("Test " + "Features file test"
74 + "\nFailed to parse features file.",
75 featuresFile.parse(al.getDataset(), colours, true));
78 * Refetch the colour map from the FeatureRenderer (to confirm it has been
79 * updated - JAL-1904), and verify (some) feature group colours
81 colours = af.getFeatureRenderer().getFeatureColours();
82 assertEquals("26 feature group colours not found", 26, colours.size());
83 assertEquals(colours.get("Cath").getColour(), new Color(0x93b1d1));
84 assertEquals(colours.get("ASX-MOTIF").getColour(), new Color(0x6addbb));
87 * verify (some) features on sequences
89 List<SequenceFeature> sfs = al.getSequenceAt(0).getDatasetSequence()
90 .getSequenceFeatures(); // FER_CAPAA
91 SequenceFeatures.sortFeatures(sfs, true);
92 assertEquals(8, sfs.size());
95 * verify (in ascending start position order)
97 SequenceFeature sf = sfs.get(0);
98 assertEquals("Pfam family%LINK%", sf.description);
99 assertEquals(0, sf.begin);
100 assertEquals(0, sf.end);
101 assertEquals("uniprot", sf.featureGroup);
102 assertEquals("Pfam", sf.type);
103 assertEquals(1, sf.links.size());
104 assertEquals("Pfam family|http://pfam.xfam.org/family/PF00111",
108 assertEquals("Ferredoxin_fold Status: True Positive ", sf.description);
109 assertEquals(3, sf.begin);
110 assertEquals(93, sf.end);
111 assertEquals("uniprot", sf.featureGroup);
112 assertEquals("Cath", sf.type);
115 assertEquals("Fer2 Status: True Positive Pfam 8_8%LINK%",
117 assertEquals("Pfam 8_8|http://pfam.xfam.org/family/PF00111",
119 assertEquals(8, sf.begin);
120 assertEquals(83, sf.end);
121 assertEquals("uniprot", sf.featureGroup);
122 assertEquals("Pfam", sf.type);
125 assertEquals("Iron-sulfur (2Fe-2S)", sf.description);
126 assertEquals(39, sf.begin);
127 assertEquals(39, sf.end);
128 assertEquals("uniprot", sf.featureGroup);
129 assertEquals("METAL", sf.type);
132 assertEquals("Iron-sulfur (2Fe-2S)", sf.description);
133 assertEquals(44, sf.begin);
134 assertEquals(44, sf.end);
135 assertEquals("uniprot", sf.featureGroup);
136 assertEquals("METAL", sf.type);
139 assertEquals("Iron-sulfur (2Fe-2S)", sf.description);
140 assertEquals(47, sf.begin);
141 assertEquals(47, sf.end);
142 assertEquals("uniprot", sf.featureGroup);
143 assertEquals("METAL", sf.type);
146 assertEquals("Iron-sulfur (2Fe-2S)", sf.description);
147 assertEquals(77, sf.begin);
148 assertEquals(77, sf.end);
149 assertEquals("uniprot", sf.featureGroup);
150 assertEquals("METAL", sf.type);
154 "High confidence server. Only hits with scores over 0.8 are reported. PHOSPHORYLATION (T) 89_8%LINK%",
157 "PHOSPHORYLATION (T) 89_8|http://www.cbs.dtu.dk/cgi-bin/proview/webface-link?seqid=P83527&service=NetPhos-2.0",
159 assertEquals(89, sf.begin);
160 assertEquals(89, sf.end);
161 assertEquals("netphos", sf.featureGroup);
162 assertEquals("PHOSPHORYLATION (T)", sf.type);
166 * Test parsing a features file with a mix of Jalview and GFF formatted
171 @Test(groups = { "Functional" })
172 public void testParse_mixedJalviewGff() throws Exception
174 File f = new File("examples/uniref50.fa");
175 AlignmentI al = readAlignmentFile(f);
176 AlignFrame af = new AlignFrame(al, 500, 500);
177 Map<String, FeatureColourI> colours = af.getFeatureRenderer()
178 .getFeatureColours();
179 // GFF2 uses space as name/value separator in column 9
180 String gffData = "METAL\tcc9900\n"
182 + "FER_CAPAA\tuniprot\tMETAL\t44\t45\t4.0\t.\t.\tNote Iron-sulfur; Note 2Fe-2S\n"
183 + "FER1_SOLLC\tuniprot\tPfam\t55\t130\t2.0\t.\t.";
184 FeaturesFile featuresFile = new FeaturesFile(gffData,
185 DataSourceType.PASTE);
186 assertTrue("Failed to parse features file",
187 featuresFile.parse(al.getDataset(), colours, true));
189 // verify colours read or synthesized
190 colours = af.getFeatureRenderer().getFeatureColours();
191 assertEquals("1 feature group colours not found", 1, colours.size());
192 assertEquals(colours.get("METAL").getColour(), new Color(0xcc9900));
194 // verify feature on FER_CAPAA
195 List<SequenceFeature> sfs = al.getSequenceAt(0).getDatasetSequence()
196 .getSequenceFeatures();
197 assertEquals(1, sfs.size());
198 SequenceFeature sf = sfs.get(0);
199 assertEquals("Iron-sulfur,2Fe-2S", sf.description);
200 assertEquals(44, sf.begin);
201 assertEquals(45, sf.end);
202 assertEquals("uniprot", sf.featureGroup);
203 assertEquals("METAL", sf.type);
204 assertEquals(4f, sf.getScore(), 0.001f);
206 // verify feature on FER1_SOLLC
207 sfs = al.getSequenceAt(2).getDatasetSequence().getSequenceFeatures();
208 assertEquals(1, sfs.size());
210 assertEquals("uniprot", sf.description);
211 assertEquals(55, sf.begin);
212 assertEquals(130, sf.end);
213 assertEquals("uniprot", sf.featureGroup);
214 assertEquals("Pfam", sf.type);
215 assertEquals(2f, sf.getScore(), 0.001f);
218 public static AlignmentI readAlignmentFile(File f) throws IOException
220 System.out.println("Reading file: " + f);
221 String ff = f.getPath();
222 FormatAdapter rf = new FormatAdapter();
224 AlignmentI al = rf.readFile(ff, DataSourceType.FILE,
225 new IdentifyFile().identify(ff, DataSourceType.FILE));
227 al.setDataset(null); // creates dataset sequences
228 assertNotNull("Couldn't read supplied alignment data.", al);
233 * Test parsing a features file with GFF formatted content only
237 @Test(groups = { "Functional" })
238 public void testParse_pureGff3() throws Exception
240 File f = new File("examples/uniref50.fa");
241 AlignmentI al = readAlignmentFile(f);
242 AlignFrame af = new AlignFrame(al, 500, 500);
243 Map<String, FeatureColourI> colours = af.getFeatureRenderer()
244 .getFeatureColours();
245 // GFF3 uses '=' separator for name/value pairs in colum 9
246 String gffData = "##gff-version 3\n"
247 + "FER_CAPAA\tuniprot\tMETAL\t39\t39\t0.0\t.\t.\t"
248 + "Note=Iron-sulfur (2Fe-2S);Note=another note;evidence=ECO:0000255|PROSITE-ProRule:PRU00465\n"
249 + "FER1_SOLLC\tuniprot\tPfam\t55\t130\t3.0\t.\t.\tID=$23";
250 FeaturesFile featuresFile = new FeaturesFile(gffData,
251 DataSourceType.PASTE);
252 assertTrue("Failed to parse features file",
253 featuresFile.parse(al.getDataset(), colours, true));
255 // verify feature on FER_CAPAA
256 List<SequenceFeature> sfs = al.getSequenceAt(0).getDatasetSequence()
257 .getSequenceFeatures();
258 assertEquals(1, sfs.size());
259 SequenceFeature sf = sfs.get(0);
260 // description parsed from Note attribute
261 assertEquals("Iron-sulfur (2Fe-2S),another note", sf.description);
262 assertEquals(39, sf.begin);
263 assertEquals(39, sf.end);
264 assertEquals("uniprot", sf.featureGroup);
265 assertEquals("METAL", sf.type);
267 "Note=Iron-sulfur (2Fe-2S);Note=another note;evidence=ECO:0000255|PROSITE-ProRule:PRU00465",
268 sf.getValue("ATTRIBUTES"));
270 // verify feature on FER1_SOLLC1
271 sfs = al.getSequenceAt(2).getDatasetSequence().getSequenceFeatures();
272 assertEquals(1, sfs.size());
274 // ID used for description if available
275 assertEquals("$23", sf.description);
276 assertEquals(55, sf.begin);
277 assertEquals(130, sf.end);
278 assertEquals("uniprot", sf.featureGroup);
279 assertEquals("Pfam", sf.type);
280 assertEquals(3f, sf.getScore(), 0.001f);
284 * Test parsing a features file with Jalview format features (but no colour
285 * descriptors or startgroup to give the hint not to parse as GFF)
289 @Test(groups = { "Functional" })
290 public void testParse_jalviewFeaturesOnly() throws Exception
292 File f = new File("examples/uniref50.fa");
293 AlignmentI al = readAlignmentFile(f);
294 AlignFrame af = new AlignFrame(al, 500, 500);
295 Map<String, FeatureColourI> colours = af.getFeatureRenderer()
296 .getFeatureColours();
299 * one feature on FER_CAPAA and one on sequence 3 (index 2) FER1_SOLLC
301 String featureData = "Iron-sulfur (2Fe-2S)\tFER_CAPAA\t-1\t39\t39\tMETAL\n"
302 + "Iron-phosphorus (2Fe-P)\tID_NOT_SPECIFIED\t2\t86\t87\tMETALLIC\n";
303 FeaturesFile featuresFile = new FeaturesFile(featureData,
304 DataSourceType.PASTE);
305 assertTrue("Failed to parse features file",
306 featuresFile.parse(al.getDataset(), colours, true));
308 // verify FER_CAPAA feature
309 List<SequenceFeature> sfs = al.getSequenceAt(0).getDatasetSequence()
310 .getSequenceFeatures();
311 assertEquals(1, sfs.size());
312 SequenceFeature sf = sfs.get(0);
313 assertEquals("Iron-sulfur (2Fe-2S)", sf.description);
314 assertEquals(39, sf.begin);
315 assertEquals(39, sf.end);
316 assertEquals("METAL", sf.type);
318 // verify FER1_SOLLC feature
319 sfs = al.getSequenceAt(2).getDatasetSequence().getSequenceFeatures();
320 assertEquals(1, sfs.size());
322 assertEquals("Iron-phosphorus (2Fe-P)", sf.description);
323 assertEquals(86, sf.begin);
324 assertEquals(87, sf.end);
325 assertEquals("METALLIC", sf.type);
328 private void checkDatasetfromSimpleGff3(AlignmentI dataset)
330 assertEquals("no sequences extracted from GFF3 file", 2,
331 dataset.getHeight());
333 SequenceI seq1 = dataset.findName("seq1");
334 SequenceI seq2 = dataset.findName("seq2");
338 "Failed to replace dummy seq1 with real sequence",
339 seq1 instanceof SequenceDummy
340 && ((SequenceDummy) seq1).isDummy());
342 "Failed to replace dummy seq2 with real sequence",
343 seq2 instanceof SequenceDummy
344 && ((SequenceDummy) seq2).isDummy());
345 String placeholderseq = new SequenceDummy("foo").getSequenceAsString();
346 assertFalse("dummy replacement buggy for seq1",
347 placeholderseq.equals(seq1.getSequenceAsString()));
348 assertFalse("dummy replacement buggy for seq2",
349 placeholderseq.equals(seq2.getSequenceAsString()));
350 assertNotNull("No features added to seq1", seq1.getSequenceFeatures());
351 assertEquals("Wrong number of features", 3, seq1.getSequenceFeatures()
353 assertTrue(seq2.getSequenceFeatures().isEmpty());
355 "Wrong number of features",
357 seq2.getSequenceFeatures() == null ? 0 : seq2
358 .getSequenceFeatures().size());
360 "Expected at least one CDNA/Protein mapping for seq1",
361 dataset.getCodonFrame(seq1) != null
362 && dataset.getCodonFrame(seq1).size() > 0);
366 @Test(groups = { "Functional" })
367 public void readGff3File() throws IOException
369 FeaturesFile gffreader = new FeaturesFile(true, simpleGffFile,
370 DataSourceType.FILE);
371 Alignment dataset = new Alignment(gffreader.getSeqsAsArray());
372 gffreader.addProperties(dataset);
373 checkDatasetfromSimpleGff3(dataset);
376 @Test(groups = { "Functional" })
377 public void simpleGff3FileClass() throws IOException
379 AlignmentI dataset = new Alignment(new SequenceI[] {});
380 FeaturesFile ffile = new FeaturesFile(simpleGffFile,
381 DataSourceType.FILE);
383 boolean parseResult = ffile.parse(dataset, null, false, false);
384 assertTrue("return result should be true", parseResult);
385 checkDatasetfromSimpleGff3(dataset);
388 @Test(groups = { "Functional" })
389 public void simpleGff3FileLoader() throws IOException
391 AlignFrame af = new FileLoader(false).LoadFileWaitTillLoaded(
392 simpleGffFile, DataSourceType.FILE);
394 "Didn't read the alignment into an alignframe from Gff3 File",
396 checkDatasetfromSimpleGff3(af.getViewport().getAlignment());
399 @Test(groups = { "Functional" })
400 public void simpleGff3RelaxedIdMatching() throws IOException
402 AlignmentI dataset = new Alignment(new SequenceI[] {});
403 FeaturesFile ffile = new FeaturesFile(simpleGffFile,
404 DataSourceType.FILE);
406 boolean parseResult = ffile.parse(dataset, null, false, true);
407 assertTrue("return result (relaxedID matching) should be true",
409 checkDatasetfromSimpleGff3(dataset);
412 @Test(groups = { "Functional" })
413 public void testPrintJalviewFormat() throws Exception
415 File f = new File("examples/uniref50.fa");
416 AlignmentI al = readAlignmentFile(f);
417 AlignFrame af = new AlignFrame(al, 500, 500);
418 Map<String, FeatureColourI> colours = af.getFeatureRenderer()
419 .getFeatureColours();
420 String features = "METAL\tcc9900\n"
421 + "GAMMA-TURN\tred|0,255,255|20.0|95.0|below|66.0\n"
423 + "STARTGROUP\tuniprot\n"
424 + "Cath\tFER_CAPAA\t-1\t0\t0\tDomain\n" // non-positional feature
425 + "Iron\tFER_CAPAA\t-1\t39\t39\tMETAL\n"
426 + "Turn\tFER_CAPAA\t-1\t36\t38\tGAMMA-TURN\n"
427 + "<html>Pfam domain<a href=\"http://pfam.xfam.org/family/PF00111\">Pfam_3_4</a></html>\tFER_CAPAA\t-1\t20\t20\tPfam\n"
428 + "ENDGROUP\tuniprot\n";
429 FeaturesFile featuresFile = new FeaturesFile(features,
430 DataSourceType.PASTE);
431 featuresFile.parse(al.getDataset(), colours, false);
434 * add positional and non-positional features with null and
435 * empty feature group to check handled correctly
437 SequenceI seq = al.getSequenceAt(1); // FER_CAPAN
438 seq.addSequenceFeature(new SequenceFeature("Pfam", "desc1", 0, 0, 1.3f,
440 seq.addSequenceFeature(new SequenceFeature("Pfam", "desc2", 4, 9,
442 seq = al.getSequenceAt(2); // FER1_SOLLC
443 seq.addSequenceFeature(new SequenceFeature("Pfam", "desc3", 0, 0,
445 seq.addSequenceFeature(new SequenceFeature("Pfam", "desc4", 5, 8,
449 * first with no features displayed, exclude non-positional features
451 FeatureRenderer fr = af.alignPanel.getFeatureRenderer();
452 Map<String, FeatureColourI> visible = fr.getDisplayedFeatureCols();
453 List<String> visibleGroups = new ArrayList<String>(
454 Arrays.asList(new String[] {}));
455 String exported = featuresFile.printJalviewFormat(
456 al.getSequencesArray(), visible, visibleGroups, false);
457 String expected = "No Features Visible";
458 assertEquals(expected, exported);
461 * include non-positional features
463 visibleGroups.add("uniprot");
464 exported = featuresFile.printJalviewFormat(al.getSequencesArray(),
465 visible, visibleGroups, true);
466 expected = "Cath\tFER_CAPAA\t-1\t0\t0\tDomain\t0.0\n"
467 + "desc1\tFER_CAPAN\t-1\t0\t0\tPfam\t1.3\n"
468 + "desc3\tFER1_SOLLC\t-1\t0\t0\tPfam\n" // NaN is not output
469 + "\nSTARTGROUP\tuniprot\nENDGROUP\tuniprot\n";
470 assertEquals(expected, exported);
473 * set METAL (in uniprot group) and GAMMA-TURN visible, but not Pfam
475 fr.setVisible("METAL");
476 fr.setVisible("GAMMA-TURN");
477 visible = fr.getDisplayedFeatureCols();
478 exported = featuresFile.printJalviewFormat(al.getSequencesArray(),
479 visible, visibleGroups, false);
480 expected = "METAL\tcc9900\n"
481 + "GAMMA-TURN\tff0000|00ffff|20.0|95.0|below|66.0\n"
482 + "\nSTARTGROUP\tuniprot\n"
483 + "Turn\tFER_CAPAA\t-1\t36\t38\tGAMMA-TURN\t0.0\n"
484 + "Iron\tFER_CAPAA\t-1\t39\t39\tMETAL\t0.0\n"
485 + "ENDGROUP\tuniprot\n";
486 assertEquals(expected, exported);
489 * now set Pfam visible
491 fr.setVisible("Pfam");
492 visible = fr.getDisplayedFeatureCols();
493 exported = featuresFile.printJalviewFormat(al.getSequencesArray(),
494 visible, visibleGroups, false);
496 * features are output within group, ordered by sequence and by type
498 expected = "METAL\tcc9900\n"
500 + "GAMMA-TURN\tff0000|00ffff|20.0|95.0|below|66.0\n"
501 + "\nSTARTGROUP\tuniprot\n"
502 + "Turn\tFER_CAPAA\t-1\t36\t38\tGAMMA-TURN\t0.0\n"
503 + "Iron\tFER_CAPAA\t-1\t39\t39\tMETAL\t0.0\n"
504 + "<html>Pfam domain<a href=\"http://pfam.xfam.org/family/PF00111\">Pfam_3_4</a></html>\tFER_CAPAA\t-1\t20\t20\tPfam\t0.0\n"
505 + "ENDGROUP\tuniprot\n"
506 // null / empty group features output after features in named
508 + "desc2\tFER_CAPAN\t-1\t4\t9\tPfam\n"
509 + "desc4\tFER1_SOLLC\t-1\t5\t8\tPfam\t-2.6\n";
510 assertEquals(expected, exported);
513 @Test(groups = { "Functional" })
514 public void testPrintGffFormat() throws Exception
516 File f = new File("examples/uniref50.fa");
517 AlignmentI al = readAlignmentFile(f);
518 AlignFrame af = new AlignFrame(al, 500, 500);
523 FeaturesFile featuresFile = new FeaturesFile();
524 FeatureRenderer fr = af.alignPanel.getFeatureRenderer();
525 Map<String, FeatureColourI> visible = new HashMap<String, FeatureColourI>();
526 List<String> visibleGroups = new ArrayList<String>(
527 Arrays.asList(new String[] {}));
528 String exported = featuresFile.printGffFormat(al.getSequencesArray(),
529 visible, visibleGroups, false);
530 String gffHeader = "##gff-version 2\n";
531 assertEquals(gffHeader, exported);
532 exported = featuresFile.printGffFormat(al.getSequencesArray(), visible,
533 visibleGroups, true);
534 assertEquals(gffHeader, exported);
539 al.getSequenceAt(0).addSequenceFeature(
540 new SequenceFeature("Domain", "Cath", 0, 0, 0f, "Uniprot"));
541 al.getSequenceAt(0).addSequenceFeature(
542 new SequenceFeature("METAL", "Cath", 39, 39, 1.2f, null));
545 new SequenceFeature("GAMMA-TURN", "Turn", 36, 38, 2.1f,
547 SequenceFeature sf = new SequenceFeature("Pfam", "", 20, 20, 0f,
549 sf.setAttributes("x=y;black=white");
552 al.getSequenceAt(1).addSequenceFeature(sf);
555 * with no features displayed, exclude non-positional features
557 exported = featuresFile.printGffFormat(al.getSequencesArray(), visible,
558 visibleGroups, false);
559 assertEquals(gffHeader, exported);
562 * include non-positional features
564 visibleGroups.add("Uniprot");
565 exported = featuresFile.printGffFormat(al.getSequencesArray(), visible,
566 visibleGroups, true);
567 String expected = gffHeader
568 + "FER_CAPAA\tUniprot\tDomain\t0\t0\t0.0\t.\t.\n";
569 assertEquals(expected, exported);
572 * set METAL (in uniprot group) and GAMMA-TURN visible, but not Pfam
573 * only Uniprot group visible here...
575 fr.setVisible("METAL");
576 fr.setVisible("GAMMA-TURN");
577 visible = fr.getDisplayedFeatureCols();
578 exported = featuresFile.printGffFormat(al.getSequencesArray(), visible,
579 visibleGroups, false);
580 // METAL feature has null group: description used for column 2
581 expected = gffHeader + "FER_CAPAA\tCath\tMETAL\t39\t39\t1.2\t.\t.\n";
582 assertEquals(expected, exported);
585 * set s3dm group visible
587 visibleGroups.add("s3dm");
588 exported = featuresFile.printGffFormat(al.getSequencesArray(), visible,
589 visibleGroups, false);
590 // METAL feature has null group: description used for column 2
591 expected = gffHeader + "FER_CAPAA\tCath\tMETAL\t39\t39\t1.2\t.\t.\n"
592 + "FER_CAPAN\ts3dm\tGAMMA-TURN\t36\t38\t2.1\t.\t.\n";
593 assertEquals(expected, exported);
596 * now set Pfam visible
598 fr.setVisible("Pfam");
599 visible = fr.getDisplayedFeatureCols();
600 exported = featuresFile.printGffFormat(al.getSequencesArray(), visible,
601 visibleGroups, false);
602 // Pfam feature columns include strand(+), phase(2), attributes
604 + "FER_CAPAA\tCath\tMETAL\t39\t39\t1.2\t.\t.\n"
605 + "FER_CAPAN\ts3dm\tGAMMA-TURN\t36\t38\t2.1\t.\t.\n"
606 + "FER_CAPAN\tUniprot\tPfam\t20\t20\t0.0\t+\t2\tx=y;black=white\n";
607 assertEquals(expected, exported);