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.Desktop;
38 import jalview.gui.JvOptionPane;
39 import jalview.structure.StructureSelectionManager;
41 import java.awt.Color;
43 import java.io.IOException;
44 import java.util.ArrayList;
45 import java.util.Arrays;
46 import java.util.HashMap;
47 import java.util.List;
50 import org.testng.annotations.AfterClass;
51 import org.testng.annotations.BeforeClass;
52 import org.testng.annotations.Test;
54 public class FeaturesFileTest
56 private static String simpleGffFile = "examples/testdata/simpleGff3.gff";
58 @AfterClass(alwaysRun = true)
59 public void tearDownAfterClass()
62 * remove any sequence mappings created so they don't pollute other tests
64 StructureSelectionManager ssm = StructureSelectionManager
65 .getStructureSelectionManager(Desktop.instance);
69 @BeforeClass(alwaysRun = true)
70 public void setUpJvOptionPane()
72 JvOptionPane.setInteractiveMode(false);
73 JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
76 @Test(groups = { "Functional" })
77 public void testParse() throws Exception
79 File f = new File("examples/uniref50.fa");
80 AlignmentI al = readAlignmentFile(f);
81 AlignFrame af = new AlignFrame(al, 500, 500);
82 Map<String, FeatureColourI> colours = af.getFeatureRenderer()
84 FeaturesFile featuresFile = new FeaturesFile(
85 "examples/exampleFeatures.txt", DataSourceType.FILE);
86 assertTrue("Test " + "Features file test"
87 + "\nFailed to parse features file.",
88 featuresFile.parse(al.getDataset(), colours, true));
91 * Refetch the colour map from the FeatureRenderer (to confirm it has been
92 * updated - JAL-1904), and verify (some) feature group colours
94 colours = af.getFeatureRenderer().getFeatureColours();
95 assertEquals("27 feature group colours not found", 27, colours.size());
96 assertEquals(colours.get("Cath").getColour(), new Color(0x93b1d1));
97 assertEquals(colours.get("ASX-MOTIF").getColour(), new Color(0x6addbb));
98 FeatureColourI kdColour = colours.get("kdHydrophobicity");
99 assertTrue(kdColour.isGraduatedColour());
100 assertTrue(kdColour.isAboveThreshold());
101 assertEquals(-2f, kdColour.getThreshold());
104 * verify (some) features on sequences
106 List<SequenceFeature> sfs = al.getSequenceAt(0).getDatasetSequence()
107 .getSequenceFeatures(); // FER_CAPAA
108 SequenceFeatures.sortFeatures(sfs, true);
109 assertEquals(8, sfs.size());
112 * verify (in ascending start position order)
114 SequenceFeature sf = sfs.get(0);
115 assertEquals("Pfam family%LINK%", sf.description);
116 assertEquals(0, sf.begin);
117 assertEquals(0, sf.end);
118 assertEquals("uniprot", sf.featureGroup);
119 assertEquals("Pfam", sf.type);
120 assertEquals(1, sf.links.size());
121 assertEquals("Pfam family|http://pfam.xfam.org/family/PF00111",
125 assertEquals("Ferredoxin_fold Status: True Positive ", sf.description);
126 assertEquals(3, sf.begin);
127 assertEquals(93, sf.end);
128 assertEquals("uniprot", sf.featureGroup);
129 assertEquals("Cath", sf.type);
132 assertEquals("Fer2 Status: True Positive Pfam 8_8%LINK%",
134 assertEquals("Pfam 8_8|http://pfam.xfam.org/family/PF00111",
136 assertEquals(8, sf.begin);
137 assertEquals(83, sf.end);
138 assertEquals("uniprot", sf.featureGroup);
139 assertEquals("Pfam", sf.type);
142 assertEquals("Iron-sulfur (2Fe-2S)", sf.description);
143 assertEquals(39, sf.begin);
144 assertEquals(39, sf.end);
145 assertEquals("uniprot", sf.featureGroup);
146 assertEquals("METAL", sf.type);
149 assertEquals("Iron-sulfur (2Fe-2S)", sf.description);
150 assertEquals(44, sf.begin);
151 assertEquals(44, sf.end);
152 assertEquals("uniprot", sf.featureGroup);
153 assertEquals("METAL", sf.type);
156 assertEquals("Iron-sulfur (2Fe-2S)", sf.description);
157 assertEquals(47, sf.begin);
158 assertEquals(47, sf.end);
159 assertEquals("uniprot", sf.featureGroup);
160 assertEquals("METAL", sf.type);
163 assertEquals("Iron-sulfur (2Fe-2S)", sf.description);
164 assertEquals(77, sf.begin);
165 assertEquals(77, sf.end);
166 assertEquals("uniprot", sf.featureGroup);
167 assertEquals("METAL", sf.type);
171 "High confidence server. Only hits with scores over 0.8 are reported. PHOSPHORYLATION (T) 89_8%LINK%",
174 "PHOSPHORYLATION (T) 89_8|http://www.cbs.dtu.dk/cgi-bin/proview/webface-link?seqid=P83527&service=NetPhos-2.0",
176 assertEquals(89, sf.begin);
177 assertEquals(89, sf.end);
178 assertEquals("netphos", sf.featureGroup);
179 assertEquals("PHOSPHORYLATION (T)", sf.type);
183 * Test parsing a features file with a mix of Jalview and GFF formatted
188 @Test(groups = { "Functional" })
189 public void testParse_mixedJalviewGff() throws Exception
191 File f = new File("examples/uniref50.fa");
192 AlignmentI al = readAlignmentFile(f);
193 AlignFrame af = new AlignFrame(al, 500, 500);
194 Map<String, FeatureColourI> colours = af.getFeatureRenderer()
195 .getFeatureColours();
196 // GFF2 uses space as name/value separator in column 9
197 String gffData = "METAL\tcc9900\n"
199 + "FER_CAPAA\tuniprot\tMETAL\t44\t45\t4.0\t.\t.\tNote Iron-sulfur; Note 2Fe-2S\n"
200 + "FER1_SOLLC\tuniprot\tPfam\t55\t130\t2.0\t.\t.";
201 FeaturesFile featuresFile = new FeaturesFile(gffData,
202 DataSourceType.PASTE);
203 assertTrue("Failed to parse features file",
204 featuresFile.parse(al.getDataset(), colours, true));
206 // verify colours read or synthesized
207 colours = af.getFeatureRenderer().getFeatureColours();
208 assertEquals("1 feature group colours not found", 1, colours.size());
209 assertEquals(colours.get("METAL").getColour(), new Color(0xcc9900));
211 // verify feature on FER_CAPAA
212 List<SequenceFeature> sfs = al.getSequenceAt(0).getDatasetSequence()
213 .getSequenceFeatures();
214 assertEquals(1, sfs.size());
215 SequenceFeature sf = sfs.get(0);
216 assertEquals("Iron-sulfur,2Fe-2S", sf.description);
217 assertEquals(44, sf.begin);
218 assertEquals(45, sf.end);
219 assertEquals("uniprot", sf.featureGroup);
220 assertEquals("METAL", sf.type);
221 assertEquals(4f, sf.getScore(), 0.001f);
223 // verify feature on FER1_SOLLC
224 sfs = al.getSequenceAt(2).getDatasetSequence().getSequenceFeatures();
225 assertEquals(1, sfs.size());
227 assertEquals("uniprot", sf.description);
228 assertEquals(55, sf.begin);
229 assertEquals(130, sf.end);
230 assertEquals("uniprot", sf.featureGroup);
231 assertEquals("Pfam", sf.type);
232 assertEquals(2f, sf.getScore(), 0.001f);
235 public static AlignmentI readAlignmentFile(File f) throws IOException
237 System.out.println("Reading file: " + f);
238 String ff = f.getPath();
239 FormatAdapter rf = new FormatAdapter();
241 AlignmentI al = rf.readFile(ff, DataSourceType.FILE,
242 new IdentifyFile().identify(ff, DataSourceType.FILE));
244 al.setDataset(null); // creates dataset sequences
245 assertNotNull("Couldn't read supplied alignment data.", al);
250 * Test parsing a features file with GFF formatted content only
254 @Test(groups = { "Functional" })
255 public void testParse_pureGff3() throws Exception
257 File f = new File("examples/uniref50.fa");
258 AlignmentI al = readAlignmentFile(f);
259 AlignFrame af = new AlignFrame(al, 500, 500);
260 Map<String, FeatureColourI> colours = af.getFeatureRenderer()
261 .getFeatureColours();
262 // GFF3 uses '=' separator for name/value pairs in colum 9
263 String gffData = "##gff-version 3\n"
264 + "FER_CAPAA\tuniprot\tMETAL\t39\t39\t0.0\t.\t.\t"
265 + "Note=Iron-sulfur (2Fe-2S);Note=another note;evidence=ECO:0000255|PROSITE-ProRule:PRU00465\n"
266 + "FER1_SOLLC\tuniprot\tPfam\t55\t130\t3.0\t.\t.\tID=$23";
267 FeaturesFile featuresFile = new FeaturesFile(gffData,
268 DataSourceType.PASTE);
269 assertTrue("Failed to parse features file",
270 featuresFile.parse(al.getDataset(), colours, true));
272 // verify feature on FER_CAPAA
273 List<SequenceFeature> sfs = al.getSequenceAt(0).getDatasetSequence()
274 .getSequenceFeatures();
275 assertEquals(1, sfs.size());
276 SequenceFeature sf = sfs.get(0);
277 // description parsed from Note attribute
278 assertEquals("Iron-sulfur (2Fe-2S),another note", sf.description);
279 assertEquals(39, sf.begin);
280 assertEquals(39, sf.end);
281 assertEquals("uniprot", sf.featureGroup);
282 assertEquals("METAL", sf.type);
284 "Note=Iron-sulfur (2Fe-2S);Note=another note;evidence=ECO:0000255|PROSITE-ProRule:PRU00465",
285 sf.getValue("ATTRIBUTES"));
287 // verify feature on FER1_SOLLC1
288 sfs = al.getSequenceAt(2).getDatasetSequence().getSequenceFeatures();
289 assertEquals(1, sfs.size());
291 // ID used for description if available
292 assertEquals("$23", sf.description);
293 assertEquals(55, sf.begin);
294 assertEquals(130, sf.end);
295 assertEquals("uniprot", sf.featureGroup);
296 assertEquals("Pfam", sf.type);
297 assertEquals(3f, sf.getScore(), 0.001f);
301 * Test parsing a features file with Jalview format features (but no colour
302 * descriptors or startgroup to give the hint not to parse as GFF)
306 @Test(groups = { "Functional" })
307 public void testParse_jalviewFeaturesOnly() throws Exception
309 File f = new File("examples/uniref50.fa");
310 AlignmentI al = readAlignmentFile(f);
311 AlignFrame af = new AlignFrame(al, 500, 500);
312 Map<String, FeatureColourI> colours = af.getFeatureRenderer()
313 .getFeatureColours();
316 * one feature on FER_CAPAA and one on sequence 3 (index 2) FER1_SOLLC
318 String featureData = "Iron-sulfur (2Fe-2S)\tFER_CAPAA\t-1\t39\t39\tMETAL\n"
319 + "Iron-phosphorus (2Fe-P)\tID_NOT_SPECIFIED\t2\t86\t87\tMETALLIC\n";
320 FeaturesFile featuresFile = new FeaturesFile(featureData,
321 DataSourceType.PASTE);
322 assertTrue("Failed to parse features file",
323 featuresFile.parse(al.getDataset(), colours, true));
325 // verify FER_CAPAA feature
326 List<SequenceFeature> sfs = al.getSequenceAt(0).getDatasetSequence()
327 .getSequenceFeatures();
328 assertEquals(1, sfs.size());
329 SequenceFeature sf = sfs.get(0);
330 assertEquals("Iron-sulfur (2Fe-2S)", sf.description);
331 assertEquals(39, sf.begin);
332 assertEquals(39, sf.end);
333 assertEquals("METAL", sf.type);
335 // verify FER1_SOLLC feature
336 sfs = al.getSequenceAt(2).getDatasetSequence().getSequenceFeatures();
337 assertEquals(1, sfs.size());
339 assertEquals("Iron-phosphorus (2Fe-P)", sf.description);
340 assertEquals(86, sf.begin);
341 assertEquals(87, sf.end);
342 assertEquals("METALLIC", sf.type);
345 private void checkDatasetfromSimpleGff3(AlignmentI dataset)
347 assertEquals("no sequences extracted from GFF3 file", 2,
348 dataset.getHeight());
350 SequenceI seq1 = dataset.findName("seq1");
351 SequenceI seq2 = dataset.findName("seq2");
355 "Failed to replace dummy seq1 with real sequence",
356 seq1 instanceof SequenceDummy
357 && ((SequenceDummy) seq1).isDummy());
359 "Failed to replace dummy seq2 with real sequence",
360 seq2 instanceof SequenceDummy
361 && ((SequenceDummy) seq2).isDummy());
362 String placeholderseq = new SequenceDummy("foo").getSequenceAsString();
363 assertFalse("dummy replacement buggy for seq1",
364 placeholderseq.equals(seq1.getSequenceAsString()));
365 assertFalse("dummy replacement buggy for seq2",
366 placeholderseq.equals(seq2.getSequenceAsString()));
367 assertNotNull("No features added to seq1", seq1.getSequenceFeatures());
368 assertEquals("Wrong number of features", 3, seq1.getSequenceFeatures()
370 assertTrue(seq2.getSequenceFeatures().isEmpty());
372 "Wrong number of features",
374 seq2.getSequenceFeatures() == null ? 0 : seq2
375 .getSequenceFeatures().size());
377 "Expected at least one CDNA/Protein mapping for seq1",
378 dataset.getCodonFrame(seq1) != null
379 && dataset.getCodonFrame(seq1).size() > 0);
383 @Test(groups = { "Functional" })
384 public void readGff3File() throws IOException
386 FeaturesFile gffreader = new FeaturesFile(true, simpleGffFile,
387 DataSourceType.FILE);
388 Alignment dataset = new Alignment(gffreader.getSeqsAsArray());
389 gffreader.addProperties(dataset);
390 checkDatasetfromSimpleGff3(dataset);
393 @Test(groups = { "Functional" })
394 public void simpleGff3FileClass() throws IOException
396 AlignmentI dataset = new Alignment(new SequenceI[] {});
397 FeaturesFile ffile = new FeaturesFile(simpleGffFile,
398 DataSourceType.FILE);
400 boolean parseResult = ffile.parse(dataset, null, false, false);
401 assertTrue("return result should be true", parseResult);
402 checkDatasetfromSimpleGff3(dataset);
405 @Test(groups = { "Functional" })
406 public void simpleGff3FileLoader() throws IOException
408 AlignFrame af = new FileLoader(false).LoadFileWaitTillLoaded(
409 simpleGffFile, DataSourceType.FILE);
411 "Didn't read the alignment into an alignframe from Gff3 File",
413 checkDatasetfromSimpleGff3(af.getViewport().getAlignment());
416 @Test(groups = { "Functional" })
417 public void simpleGff3RelaxedIdMatching() throws IOException
419 AlignmentI dataset = new Alignment(new SequenceI[] {});
420 FeaturesFile ffile = new FeaturesFile(simpleGffFile,
421 DataSourceType.FILE);
423 boolean parseResult = ffile.parse(dataset, null, false, true);
424 assertTrue("return result (relaxedID matching) should be true",
426 checkDatasetfromSimpleGff3(dataset);
429 @Test(groups = { "Functional" })
430 public void testPrintJalviewFormat() throws Exception
432 File f = new File("examples/uniref50.fa");
433 AlignmentI al = readAlignmentFile(f);
434 AlignFrame af = new AlignFrame(al, 500, 500);
435 Map<String, FeatureColourI> colours = af.getFeatureRenderer()
436 .getFeatureColours();
437 String features = "METAL\tcc9900\n"
438 + "GAMMA-TURN\tred|0,255,255|20.0|95.0|below|66.0\n"
440 + "STARTGROUP\tuniprot\n"
441 + "Cath\tFER_CAPAA\t-1\t0\t0\tDomain\n" // non-positional feature
442 + "Iron\tFER_CAPAA\t-1\t39\t39\tMETAL\n"
443 + "Turn\tFER_CAPAA\t-1\t36\t38\tGAMMA-TURN\n"
444 + "<html>Pfam domain<a href=\"http://pfam.xfam.org/family/PF00111\">Pfam_3_4</a></html>\tFER_CAPAA\t-1\t20\t20\tPfam\n"
445 + "ENDGROUP\tuniprot\n";
446 FeaturesFile featuresFile = new FeaturesFile(features,
447 DataSourceType.PASTE);
448 featuresFile.parse(al.getDataset(), colours, false);
451 * add positional and non-positional features with null and
452 * empty feature group to check handled correctly
454 SequenceI seq = al.getSequenceAt(1); // FER_CAPAN
455 seq.addSequenceFeature(new SequenceFeature("Pfam", "desc1", 0, 0, 1.3f,
457 seq.addSequenceFeature(new SequenceFeature("Pfam", "desc2", 4, 9,
459 seq = al.getSequenceAt(2); // FER1_SOLLC
460 seq.addSequenceFeature(new SequenceFeature("Pfam", "desc3", 0, 0,
462 seq.addSequenceFeature(new SequenceFeature("Pfam", "desc4", 5, 8,
466 * first with no features displayed, exclude non-positional features
468 FeatureRenderer fr = af.alignPanel.getFeatureRenderer();
469 Map<String, FeatureColourI> visible = fr.getDisplayedFeatureCols();
470 List<String> visibleGroups = new ArrayList<String>(
471 Arrays.asList(new String[] {}));
472 String exported = featuresFile.printJalviewFormat(
473 al.getSequencesArray(), visible, visibleGroups, false);
474 String expected = "No Features Visible";
475 assertEquals(expected, exported);
478 * include non-positional features
480 visibleGroups.add("uniprot");
481 exported = featuresFile.printJalviewFormat(al.getSequencesArray(),
482 visible, visibleGroups, true);
483 expected = "Cath\tFER_CAPAA\t-1\t0\t0\tDomain\t0.0\n"
484 + "desc1\tFER_CAPAN\t-1\t0\t0\tPfam\t1.3\n"
485 + "desc3\tFER1_SOLLC\t-1\t0\t0\tPfam\n" // NaN is not output
486 + "\nSTARTGROUP\tuniprot\nENDGROUP\tuniprot\n";
487 assertEquals(expected, exported);
490 * set METAL (in uniprot group) and GAMMA-TURN visible, but not Pfam
492 fr.setVisible("METAL");
493 fr.setVisible("GAMMA-TURN");
494 visible = fr.getDisplayedFeatureCols();
495 exported = featuresFile.printJalviewFormat(al.getSequencesArray(),
496 visible, visibleGroups, false);
497 expected = "METAL\tcc9900\n"
498 + "GAMMA-TURN\tff0000|00ffff|20.0|95.0|below|66.0\n"
499 + "\nSTARTGROUP\tuniprot\n"
500 + "Turn\tFER_CAPAA\t-1\t36\t38\tGAMMA-TURN\t0.0\n"
501 + "Iron\tFER_CAPAA\t-1\t39\t39\tMETAL\t0.0\n"
502 + "ENDGROUP\tuniprot\n";
503 assertEquals(expected, exported);
506 * now set Pfam visible
508 fr.setVisible("Pfam");
509 visible = fr.getDisplayedFeatureCols();
510 exported = featuresFile.printJalviewFormat(al.getSequencesArray(),
511 visible, visibleGroups, false);
513 * features are output within group, ordered by sequence and by type
515 expected = "METAL\tcc9900\n"
517 + "GAMMA-TURN\tff0000|00ffff|20.0|95.0|below|66.0\n"
518 + "\nSTARTGROUP\tuniprot\n"
519 + "Turn\tFER_CAPAA\t-1\t36\t38\tGAMMA-TURN\t0.0\n"
520 + "Iron\tFER_CAPAA\t-1\t39\t39\tMETAL\t0.0\n"
521 + "<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"
522 + "ENDGROUP\tuniprot\n"
523 // null / empty group features output after features in named
525 + "desc2\tFER_CAPAN\t-1\t4\t9\tPfam\n"
526 + "desc4\tFER1_SOLLC\t-1\t5\t8\tPfam\t-2.6\n";
527 assertEquals(expected, exported);
530 @Test(groups = { "Functional" })
531 public void testPrintGffFormat() throws Exception
533 File f = new File("examples/uniref50.fa");
534 AlignmentI al = readAlignmentFile(f);
535 AlignFrame af = new AlignFrame(al, 500, 500);
540 FeaturesFile featuresFile = new FeaturesFile();
541 FeatureRenderer fr = af.alignPanel.getFeatureRenderer();
542 Map<String, FeatureColourI> visible = new HashMap<String, FeatureColourI>();
543 List<String> visibleGroups = new ArrayList<String>(
544 Arrays.asList(new String[] {}));
545 String exported = featuresFile.printGffFormat(al.getSequencesArray(),
546 visible, visibleGroups, false);
547 String gffHeader = "##gff-version 2\n";
548 assertEquals(gffHeader, exported);
549 exported = featuresFile.printGffFormat(al.getSequencesArray(), visible,
550 visibleGroups, true);
551 assertEquals(gffHeader, exported);
556 al.getSequenceAt(0).addSequenceFeature(
557 new SequenceFeature("Domain", "Cath", 0, 0, 0f, "Uniprot"));
558 al.getSequenceAt(0).addSequenceFeature(
559 new SequenceFeature("METAL", "Cath", 39, 39, 1.2f, null));
562 new SequenceFeature("GAMMA-TURN", "Turn", 36, 38, 2.1f,
564 SequenceFeature sf = new SequenceFeature("Pfam", "", 20, 20, 0f,
566 sf.setAttributes("x=y;black=white");
569 al.getSequenceAt(1).addSequenceFeature(sf);
572 * with no features displayed, exclude non-positional features
574 exported = featuresFile.printGffFormat(al.getSequencesArray(), visible,
575 visibleGroups, false);
576 assertEquals(gffHeader, exported);
579 * include non-positional features
581 visibleGroups.add("Uniprot");
582 exported = featuresFile.printGffFormat(al.getSequencesArray(), visible,
583 visibleGroups, true);
584 String expected = gffHeader
585 + "FER_CAPAA\tUniprot\tDomain\t0\t0\t0.0\t.\t.\n";
586 assertEquals(expected, exported);
589 * set METAL (in uniprot group) and GAMMA-TURN visible, but not Pfam
590 * only Uniprot group visible here...
592 fr.setVisible("METAL");
593 fr.setVisible("GAMMA-TURN");
594 visible = fr.getDisplayedFeatureCols();
595 exported = featuresFile.printGffFormat(al.getSequencesArray(), visible,
596 visibleGroups, false);
597 // METAL feature has null group: description used for column 2
598 expected = gffHeader + "FER_CAPAA\tCath\tMETAL\t39\t39\t1.2\t.\t.\n";
599 assertEquals(expected, exported);
602 * set s3dm group visible
604 visibleGroups.add("s3dm");
605 exported = featuresFile.printGffFormat(al.getSequencesArray(), visible,
606 visibleGroups, false);
607 // METAL feature has null group: description used for column 2
608 expected = gffHeader + "FER_CAPAA\tCath\tMETAL\t39\t39\t1.2\t.\t.\n"
609 + "FER_CAPAN\ts3dm\tGAMMA-TURN\t36\t38\t2.1\t.\t.\n";
610 assertEquals(expected, exported);
613 * now set Pfam visible
615 fr.setVisible("Pfam");
616 visible = fr.getDisplayedFeatureCols();
617 exported = featuresFile.printGffFormat(al.getSequencesArray(), visible,
618 visibleGroups, false);
619 // Pfam feature columns include strand(+), phase(2), attributes
621 + "FER_CAPAA\tCath\tMETAL\t39\t39\t1.2\t.\t.\n"
622 + "FER_CAPAN\ts3dm\tGAMMA-TURN\t36\t38\t2.1\t.\t.\n"
623 + "FER_CAPAN\tUniprot\tPfam\t20\t20\t0.0\t+\t2\tx=y;black=white\n";
624 assertEquals(expected, exported);