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.assertNotNull;
25 import jalview.api.AlignExportSettingI;
26 import jalview.datamodel.Alignment;
27 import jalview.datamodel.AlignmentAnnotation;
28 import jalview.datamodel.AlignmentI;
29 import jalview.datamodel.Annotation;
30 import jalview.datamodel.HiddenColumns;
31 import jalview.datamodel.Sequence;
32 import jalview.datamodel.SequenceFeature;
33 import jalview.datamodel.SequenceGroup;
34 import jalview.datamodel.SequenceI;
35 import jalview.datamodel.features.SequenceFeatures;
36 import jalview.gui.AlignFrame;
37 import jalview.gui.JvOptionPane;
38 import jalview.json.binding.biojson.v1.ColourSchemeMapper;
39 import jalview.schemes.ColourSchemeI;
40 import jalview.schemes.ResidueColourScheme;
42 import java.io.IOException;
43 import java.util.ArrayList;
44 import java.util.HashMap;
45 import java.util.List;
48 import org.testng.Assert;
49 import org.testng.AssertJUnit;
50 import org.testng.annotations.AfterTest;
51 import org.testng.annotations.BeforeClass;
52 import org.testng.annotations.BeforeMethod;
53 import org.testng.annotations.BeforeTest;
54 import org.testng.annotations.Test;
56 public class JSONFileTest
59 @BeforeClass(alwaysRun = true)
60 public void setUpJvOptionPane()
62 JvOptionPane.setInteractiveMode(false);
63 JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
66 private int TEST_SEQ_HEIGHT = 0;
68 private int TEST_GRP_HEIGHT = 0;
70 private int TEST_ANOT_HEIGHT = 0;
72 private int TEST_CS_HEIGHT = 0;
74 private String TEST_JSON_FILE = "examples/example.json";
76 private Alignment alignment;
78 private HashMap<String, SequenceI> expectedSeqs = new HashMap<>();
80 private HashMap<String, AlignmentAnnotation> expectedAnnots = new HashMap<>();
82 private HashMap<String, SequenceGroup> expectedGrps = new HashMap<>();
84 private HiddenColumns expectedColSel = new HiddenColumns();
86 private SequenceI[] expectedHiddenSeqs = new SequenceI[1];
88 private AlignmentI testAlignment;
90 private int passedCount;
92 private JSONFile testJsonFile;
96 private AlignExportSettingI exportSettings;
98 @BeforeTest(alwaysRun = true)
99 public void setup() throws Exception
102 * construct expected values
103 * nb this have to match the data in examples/example.json
105 // create and add sequences
106 Sequence[] seqs = new Sequence[5];
107 seqs[0] = new Sequence("FER_CAPAN",
108 "SVSATMISTSFMPRKPAVTSL-KPIPNVGE--ALF", 3, 34);
109 seqs[1] = new Sequence("FER1_SOLLC",
110 "SISGTMISTSFLPRKPAVTSL-KAISNVGE--ALF", 3, 34);
111 seqs[2] = new Sequence("Q93XJ9_SOLTU",
112 "SISGTMISTSFLPRKPVVTSL-KAISNVGE--ALF", 3, 34);
113 seqs[3] = new Sequence("FER1_PEA",
114 "ALYGTAVSTSFLRTQPMPMSV-TTTKAFSN--GFL", 6, 37);
115 seqs[4] = new Sequence("Q7XA98_TRIPR",
116 "ALYGTAVSTSFMRRQPVPMSV-ATTTTTKAFPSGF", 6, 39);
118 SequenceI hiddenSeq = new Sequence("FER_TOCH",
119 "FILGTMISKSFLFRKPAVTSL-KAISNVGE--ALF", 3, 34);
120 expectedHiddenSeqs[0] = hiddenSeq;
122 // create and add sequence features
123 SequenceFeature seqFeature2 = new SequenceFeature("feature_x",
124 "theDesc", 6, 15, "Jalview");
125 SequenceFeature seqFeature3 = new SequenceFeature("feature_x",
126 "theDesc", 9, 18, "Jalview");
127 SequenceFeature seqFeature4 = new SequenceFeature("feature_x",
128 "theDesc", 9, 18, "Jalview");
129 // non-positional feature:
130 SequenceFeature seqFeature5 = new SequenceFeature("Domain",
131 "My description", 0, 0, "Pfam");
132 seqs[2].addSequenceFeature(seqFeature2);
133 seqs[3].addSequenceFeature(seqFeature3);
134 seqs[4].addSequenceFeature(seqFeature4);
135 seqs[2].addSequenceFeature(seqFeature5);
137 for (Sequence seq : seqs)
139 seq.createDatasetSequence();
140 expectedSeqs.put(seq.getName(), seq);
143 // create and add a sequence group
144 List<SequenceI> grpSeqs = new ArrayList<>();
145 grpSeqs.add(seqs[1]);
146 grpSeqs.add(seqs[2]);
147 grpSeqs.add(seqs[3]);
148 grpSeqs.add(seqs[4]);
149 SequenceGroup seqGrp = new SequenceGroup(grpSeqs,
151 null, true, true, false, 21, 29);
152 ColourSchemeI scheme = ColourSchemeMapper.getJalviewColourScheme(
154 seqGrp.cs.setColourScheme(scheme);
155 seqGrp.setShowNonconserved(false);
156 seqGrp.setDescription(null);
158 expectedGrps.put(seqGrp.getName(), seqGrp);
160 // create and add annotation
161 Annotation[] annot = new Annotation[35];
162 annot[0] = new Annotation("", "", '\u0000', 0);
163 annot[1] = new Annotation("", "", '\u0000', 0);
164 annot[2] = new Annotation("α", "", 'H', 0);
165 annot[3] = new Annotation("α", "", 'H', 0);
166 annot[4] = new Annotation("α", "", 'H', 0);
167 annot[5] = new Annotation("", "", '\u0000', 0);
168 annot[6] = new Annotation("", "", '\u0000', 0);
169 annot[7] = new Annotation("", "", '\u0000', 0);
170 annot[8] = new Annotation("β", "", 'E', 0);
171 annot[9] = new Annotation("β", "", 'E', 0);
172 annot[10] = new Annotation("β", "", 'E', 0);
173 annot[11] = new Annotation("β", "", 'E', 0);
174 annot[12] = new Annotation("β", "", 'E', 0);
175 annot[13] = new Annotation("β", "", 'E', 0);
176 annot[14] = new Annotation("β", "", 'E', 0);
177 annot[15] = new Annotation("β", "", 'E', 0);
178 annot[16] = new Annotation("", "", '\u0000', 0);
179 annot[17] = new Annotation("", "", '\u0000', 0);
180 annot[18] = new Annotation("", "", '\u0000', 0);
181 annot[19] = new Annotation("", "", '\u0000', 0);
182 annot[20] = new Annotation("", "", '\u0000', 0);
183 annot[21] = new Annotation("", "", '\u0000', 0);
184 annot[22] = new Annotation("", "", '\u0000', 0);
185 annot[23] = new Annotation("", "", '\u0000', 0);
186 annot[24] = new Annotation("", "", '\u0000', 0);
187 annot[25] = new Annotation("", "", '\u0000', 0);
188 annot[26] = new Annotation("α", "", 'H', 0);
189 annot[27] = new Annotation("α", "", 'H', 0);
190 annot[28] = new Annotation("α", "", 'H', 0);
191 annot[29] = new Annotation("α", "", 'H', 0);
192 annot[30] = new Annotation("α", "", 'H', 0);
193 annot[31] = new Annotation("", "", '\u0000', 0);
194 annot[32] = new Annotation("", "", '\u0000', 0);
195 annot[33] = new Annotation("", "", '\u0000', 0);
196 annot[34] = new Annotation("", "", '\u0000', 0);
198 AlignmentAnnotation alignAnnot = new AlignmentAnnotation(
199 "Secondary Structure", "New description", annot);
200 expectedAnnots.put(alignAnnot.label, alignAnnot);
202 expectedColSel.hideColumns(32, 33);
203 expectedColSel.hideColumns(34, 34);
205 TEST_SEQ_HEIGHT = expectedSeqs.size();
206 TEST_GRP_HEIGHT = expectedGrps.size();
207 TEST_ANOT_HEIGHT = expectedAnnots.size();
208 TEST_CS_HEIGHT = expectedColSel.getHiddenColumnsCopy().size();
210 exportSettings = new AlignExportSettingI()
213 public boolean isExportHiddenSequences()
219 public boolean isExportHiddenColumns()
225 public boolean isExportGroups()
231 public boolean isExportFeatures()
237 public boolean isExportAnnotations()
243 public boolean isCancelled()
249 AppletFormatAdapter formatAdapter = new AppletFormatAdapter();
252 alignment = (Alignment) formatAdapter.readFile(TEST_JSON_FILE,
253 DataSourceType.FILE, FileFormat.Json);
254 jf = (JSONFile) formatAdapter.getAlignFile();
256 AlignFrame af = new AlignFrame(alignment, jf.getHiddenSequences(),
257 jf.getHiddenColumns(), AlignFrame.DEFAULT_WIDTH,
258 AlignFrame.DEFAULT_HEIGHT);
259 af.getViewport().setShowSequenceFeatures(jf.isShowSeqFeatures());
260 String colourSchemeName = jf.getGlobalColourScheme();
261 ColourSchemeI cs = ColourSchemeMapper.getJalviewColourScheme(
262 colourSchemeName, alignment);
264 af.getViewport().setFeaturesDisplayed(jf.getDisplayedFeatures());
266 formatAdapter = new AppletFormatAdapter(af.alignPanel, exportSettings);
267 String jsonOutput = formatAdapter.formatSequences(FileFormat.Json,
268 af.alignPanel.getAlignment(), false);
270 formatAdapter = new AppletFormatAdapter();
271 testAlignment = formatAdapter.readFile(jsonOutput,
272 DataSourceType.PASTE, FileFormat.Json);
273 testJsonFile = (JSONFile) formatAdapter.getAlignFile();
274 // System.out.println(jsonOutput);
275 } catch (IOException e)
282 @BeforeMethod(alwaysRun = true)
283 public void methodSetup()
288 @AfterTest(alwaysRun = true)
289 public void tearDown() throws Exception
294 expectedAnnots = null;
296 testAlignment = null;
300 @Test(groups = { "Functional" })
301 public void roundTripTest()
303 assertNotNull("JSON roundtrip test failed!", testJsonFile);
306 @Test(groups = { "Functional" })
307 public void testSeqParsed()
309 assertNotNull("Couldn't read supplied alignment data.", testAlignment);
310 Assert.assertNotNull(testAlignment.getSequences());
311 for (SequenceI seq : testAlignment.getSequences())
313 SequenceI expectedSeq = expectedSeqs.get(seq.getName());
314 AssertJUnit.assertTrue(
315 "Failed Sequence Test for >>> " + seq.getName(),
316 isSeqMatched(expectedSeq, seq));
319 AssertJUnit.assertEquals("Some Sequences did not pass the test",
320 TEST_SEQ_HEIGHT, passedCount);
323 @Test(groups = { "Functional" })
324 public void hiddenColsTest()
326 HiddenColumns cs = testJsonFile.getHiddenColumns();
327 Assert.assertNotNull(cs);
328 Assert.assertNotNull(cs.getHiddenColumnsCopy());
329 List<int[]> hiddenCols = cs.getHiddenColumnsCopy();
330 Assert.assertEquals(hiddenCols.size(), TEST_CS_HEIGHT);
331 Assert.assertEquals(hiddenCols.get(0), expectedColSel
332 .getHiddenColumnsCopy().get(0),
333 "Mismatched hidden columns!");
336 @Test(groups = { "Functional" })
337 public void hiddenSeqsTest()
339 Assert.assertNotNull(testJsonFile.getHiddenSequences(),
340 "Hidden sequence Expected but found Null");
341 Assert.assertEquals(jf.getHiddenSequences().length, 1,
345 @Test(groups = { "Functional" })
346 public void colorSchemeTest()
348 Assert.assertNotNull(testJsonFile.getGlobalColourScheme(),
349 "Colourscheme is null, parsing failed!");
350 Assert.assertEquals(testJsonFile.getGlobalColourScheme(), "Zappo",
351 "Zappo colour scheme expected!");
355 * Test for bug JAL-2489, NPE when exporting BioJSON with global colour
356 * scheme, and a group colour scheme, set as 'None'
358 @Test(groups = { "Functional" })
359 public void testBioJSONRoundTripWithColourSchemeNone()
361 AppletFormatAdapter formatAdapter = new AppletFormatAdapter();
363 Alignment _alignment;
366 // load example BioJSON file
367 _alignment = (Alignment) formatAdapter.readFile(TEST_JSON_FILE,
368 DataSourceType.FILE, FileFormat.Json);
369 JSONFile bioJsonFile = (JSONFile) formatAdapter.getAlignFile();
370 AlignFrame alignFrame = new AlignFrame(_alignment,
371 bioJsonFile.getHiddenSequences(),
372 bioJsonFile.getHiddenColumns(), AlignFrame.DEFAULT_WIDTH,
373 AlignFrame.DEFAULT_HEIGHT);
376 * Create a group on the alignment;
377 * Change global and group colour scheme to 'None' and perform round trip
379 SequenceGroup sg = new SequenceGroup();
380 sg.addSequence(_alignment.getSequenceAt(0), false);
381 sg.setColourScheme(null);
382 ColourSchemeI cs = ColourSchemeMapper.getJalviewColourScheme(
383 ResidueColourScheme.NONE, _alignment);
384 alignFrame.changeColour(cs);
385 alignFrame.getViewport().setFeaturesDisplayed(
386 bioJsonFile.getDisplayedFeatures());
387 formatAdapter = new AppletFormatAdapter(alignFrame.alignPanel,
389 // export BioJSON string
390 String jsonOutput = formatAdapter.formatSequences(FileFormat.Json,
391 alignFrame.alignPanel.getAlignment(), false);
392 // read back Alignment from BioJSON string
393 formatAdapter = new AppletFormatAdapter();
394 formatAdapter.readFile(jsonOutput, DataSourceType.PASTE,
396 // assert 'None' colour scheme is retained after round trip
397 JSONFile _bioJsonFile = (JSONFile) formatAdapter.getAlignFile();
398 Assert.assertEquals(_bioJsonFile.getGlobalColourScheme(),
399 ResidueColourScheme.NONE);
400 } catch (IOException e)
406 @Test(groups = { "Functional" })
407 public void isShowSeqFeaturesSet()
409 Assert.assertTrue(testJsonFile.isShowSeqFeatures(),
410 "Sequence feature isDisplayed setting expected to be true");
413 @Test(groups = { "Functional" })
414 public void testGrpParsed()
416 Assert.assertNotNull(testAlignment.getGroups());
417 for (SequenceGroup seqGrp : testAlignment.getGroups())
419 SequenceGroup expectedGrp = expectedGrps.get(seqGrp.getName());
420 AssertJUnit.assertTrue(
421 "Failed SequenceGroup Test for >>> " + seqGrp.getName(),
422 isGroupMatched(expectedGrp, seqGrp));
425 AssertJUnit.assertEquals("Some SequenceGroups did not pass the test",
426 TEST_GRP_HEIGHT, passedCount);
429 @Test(groups = { "Functional" })
430 public void testAnnotationParsed()
432 Assert.assertNotNull(testAlignment.getAlignmentAnnotation());
433 for (AlignmentAnnotation annot : testAlignment.getAlignmentAnnotation())
435 AlignmentAnnotation expectedAnnot = expectedAnnots.get(annot.label);
436 AssertJUnit.assertTrue("Failed AlignmentAnnotation Test for >>> "
437 + annot.label, isAnnotationMatched(expectedAnnot, annot));
440 AssertJUnit.assertEquals("Some Sequences did not pass the test",
441 TEST_ANOT_HEIGHT, passedCount);
444 public boolean isAnnotationMatched(AlignmentAnnotation eAnnot,
445 AlignmentAnnotation annot)
447 if (!eAnnot.label.equals(annot.label)
448 || !eAnnot.description.equals(annot.description)
449 || eAnnot.annotations.length != annot.annotations.length)
454 for (int x = 0; x < annot.annotations.length; x++)
456 Annotation y = annot.annotations[x];
457 Annotation z = annot.annotations[x];
459 if (!y.displayCharacter.equals(z.displayCharacter)
460 || y.value != z.value
461 || y.secondaryStructure != z.secondaryStructure)
469 boolean isSeqMatched(SequenceI expectedSeq, SequenceI actualSeq)
471 System.out.println("Testing >>> " + actualSeq.getName());
473 if (expectedSeq.getName().equals(actualSeq.getName())
474 && expectedSeq.getSequenceAsString().equals(
475 actualSeq.getSequenceAsString())
476 && expectedSeq.getStart() == actualSeq.getStart()
477 && expectedSeq.getEnd() == actualSeq.getEnd()
478 && featuresMatched(expectedSeq, actualSeq))
485 public boolean isGroupMatched(SequenceGroup expectedGrp,
486 SequenceGroup actualGrp)
489 System.out.println("Testing >>> " + actualGrp.getName());
490 System.out.println(expectedGrp.getName() + " | " + actualGrp.getName());
491 System.out.println(expectedGrp.getColourText() + " | "
492 + actualGrp.getColourText());
493 System.out.println(expectedGrp.getDisplayBoxes() + " | "
494 + actualGrp.getDisplayBoxes());
495 System.out.println(expectedGrp.getIgnoreGapsConsensus() + " | "
496 + actualGrp.getIgnoreGapsConsensus());
497 System.out.println(expectedGrp.getSequences().size() + " | "
498 + actualGrp.getSequences().size());
499 System.out.println(expectedGrp.getStartRes() + " | "
500 + actualGrp.getStartRes());
501 System.out.println(expectedGrp.getEndRes() + " | "
502 + actualGrp.getEndRes());
503 System.out.println(expectedGrp.cs.getColourScheme() + " | "
504 + actualGrp.cs.getColourScheme());
506 boolean colourSchemeMatches = (expectedGrp.cs.getColourScheme() == null && actualGrp.cs
507 .getColourScheme() == null)
508 || expectedGrp.cs.getColourScheme().getClass()
509 .equals(actualGrp.cs.getColourScheme().getClass());
510 if (expectedGrp.getName().equals(actualGrp.getName())
511 && expectedGrp.getColourText() == actualGrp.getColourText()
512 && expectedGrp.getDisplayBoxes() == actualGrp.getDisplayBoxes()
513 && expectedGrp.getIgnoreGapsConsensus() == actualGrp
514 .getIgnoreGapsConsensus()
515 && colourSchemeMatches
516 && expectedGrp.getSequences().size() == actualGrp
517 .getSequences().size()
518 && expectedGrp.getStartRes() == actualGrp.getStartRes()
519 && expectedGrp.getEndRes() == actualGrp.getEndRes())
526 private boolean featuresMatched(SequenceI seq1, SequenceI seq2)
530 if (seq1 == null && seq2 == null)
535 List<SequenceFeature> inFeature = seq1.getFeatures().getAllFeatures();
536 List<SequenceFeature> outFeature = seq2.getFeatures()
539 if (inFeature.size() != outFeature.size())
541 System.err.println("Feature count in: " + inFeature.size()
542 + ", out: " + outFeature.size());
546 SequenceFeatures.sortFeatures(inFeature, true);
547 SequenceFeatures.sortFeatures(outFeature, true);
549 for (SequenceFeature in : inFeature)
551 SequenceFeature out = outFeature.get(i);
553 System.out.println(out.getType() + " | " + in.getType());
554 System.out.println(out.getBegin() + " | " + in.getBegin());
555 System.out.println(out.getEnd() + " | " + in.getEnd());
559 System.err.println("Mismatch of " + in.toString() + " "
564 if (in.getBegin() == out.getBegin() && in.getEnd() == out.getEnd()
565 && in.getScore() == out.getScore()
566 && in.getFeatureGroup().equals(out.getFeatureGroup())
567 && in.getType().equals(out.getType())
568 && mapsMatch(in.otherDetails, out.otherDetails))
573 System.err.println("Feature[" + i + "] mismatch, in: "
574 + in.toString() + ", out: "
575 + outFeature.get(i).toString());
581 } catch (Exception e)
585 // System.out.println(">>>>>>>>>>>>>> features matched : " + matched);
589 boolean mapsMatch(Map<String, Object> m1, Map<String, Object> m2)
591 if (m1 == null || m2 == null)
593 if (m1 != null || m2 != null)
596 .println("only one SequenceFeature.otherDetails is not null");
604 if (m1.size() != m2.size())
606 System.err.println("otherDetails map different sizes");
609 for (String key : m1.keySet())
611 if (!m2.containsKey(key))
613 System.err.println(key + " in only one otherDetails");
616 if (m1.get(key) == null && m2.get(key) != null || m1.get(key) != null
617 && m2.get(key) == null || !m1.get(key).equals(m2.get(key)))
619 System.err.println(key + " values in otherDetails don't match");
627 * Test group roundtrip with null (None) group colour scheme
629 * @throws IOException
631 @Test(groups = { "Functional" })
632 public void testGrpParsed_colourNone() throws IOException
634 AlignmentI copy = new Alignment(testAlignment);
635 SequenceGroup sg = testAlignment.getGroups().get(0);
636 SequenceGroup copySg = new SequenceGroup(new ArrayList<SequenceI>(),
638 null, sg.getDisplayBoxes(), sg.getDisplayText(),
639 sg.getColourText(), sg.getStartRes(), sg.getEndRes());
640 for (SequenceI seq : sg.getSequences())
642 int seqIndex = testAlignment.findIndex(seq);
643 copySg.addSequence(copy.getSequenceAt(seqIndex), false);
645 copy.addGroup(copySg);
647 AlignFrame af = new AlignFrame(copy, copy.getWidth(), copy.getHeight());
648 AppletFormatAdapter formatAdapter = new AppletFormatAdapter(
650 String jsonOutput = formatAdapter.formatSequences(FileFormat.Json,
652 formatAdapter = new AppletFormatAdapter();
653 AlignmentI newAlignment = formatAdapter.readFile(jsonOutput,
654 DataSourceType.PASTE, FileFormat.Json);
656 Assert.assertNotNull(newAlignment.getGroups());
657 for (SequenceGroup seqGrp : newAlignment.getGroups())
659 SequenceGroup expectedGrp = copySg;
660 AssertJUnit.assertTrue(
661 "Failed SequenceGroup Test for >>> " + seqGrp.getName(),
662 isGroupMatched(expectedGrp, seqGrp));
665 AssertJUnit.assertEquals("Some SequenceGroups did not pass the test",
666 TEST_GRP_HEIGHT, passedCount);