c98e99e88ee84814362f9d12c35cea4e4986e8e2
[jalview.git] / test / jalview / io / JSONFileTest.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
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.
11  *  
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.
16  * 
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.
20  */
21 package jalview.io;
22
23 import static org.testng.AssertJUnit.assertNotNull;
24
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.ColumnSelection;
31 import jalview.datamodel.Sequence;
32 import jalview.datamodel.SequenceFeature;
33 import jalview.datamodel.SequenceGroup;
34 import jalview.datamodel.SequenceI;
35 import jalview.gui.AlignFrame;
36 import jalview.gui.JvOptionPane;
37 import jalview.json.binding.biojson.v1.ColourSchemeMapper;
38 import jalview.schemes.ColourSchemeI;
39 import jalview.schemes.ResidueColourScheme;
40
41 import java.io.IOException;
42 import java.util.ArrayList;
43 import java.util.HashMap;
44 import java.util.List;
45
46 import org.testng.Assert;
47 import org.testng.AssertJUnit;
48 import org.testng.annotations.AfterTest;
49 import org.testng.annotations.BeforeClass;
50 import org.testng.annotations.BeforeMethod;
51 import org.testng.annotations.BeforeTest;
52 import org.testng.annotations.Test;
53
54 public class JSONFileTest
55 {
56
57   @BeforeClass(alwaysRun = true)
58   public void setUpJvOptionPane()
59   {
60     JvOptionPane.setInteractiveMode(false);
61     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
62   }
63
64   private int TEST_SEQ_HEIGHT = 0;
65
66   private int TEST_GRP_HEIGHT = 0;
67
68   private int TEST_ANOT_HEIGHT = 0;
69
70   private int TEST_CS_HEIGHT = 0;
71
72   private String TEST_JSON_FILE = "examples/example.json";
73
74   private Alignment alignment;
75
76   private HashMap<String, SequenceI> expectedSeqs = new HashMap<String, SequenceI>();
77
78   private HashMap<String, AlignmentAnnotation> expectedAnnots = new HashMap<String, AlignmentAnnotation>();
79
80   private HashMap<String, SequenceGroup> expectedGrps = new HashMap<String, SequenceGroup>();
81
82   private ColumnSelection expectedColSel = new ColumnSelection();
83
84   private SequenceI[] expectedHiddenSeqs = new SequenceI[1];
85
86   private AlignmentI testAlignment;
87
88   private int passedCount;
89
90   private JSONFile testJsonFile;
91
92   private JSONFile jf;
93
94   private AlignExportSettingI exportSettings;
95
96   @BeforeTest(alwaysRun = true)
97   public void setup() throws Exception
98   {
99     // create and add sequences
100     Sequence[] seqs = new Sequence[5];
101     seqs[0] = new Sequence("FER_CAPAN",
102             "SVSATMISTSFMPRKPAVTSL-KPIPNVGE--ALF", 3, 34);
103     seqs[1] = new Sequence("FER1_SOLLC",
104             "SISGTMISTSFLPRKPAVTSL-KAISNVGE--ALF", 3, 34);
105     seqs[2] = new Sequence("Q93XJ9_SOLTU",
106             "SISGTMISTSFLPRKPVVTSL-KAISNVGE--ALF", 3, 34);
107     seqs[3] = new Sequence("FER1_PEA",
108             "ALYGTAVSTSFLRTQPMPMSV-TTTKAFSN--GFL", 6, 37);
109     seqs[4] = new Sequence("Q7XA98_TRIPR",
110             "ALYGTAVSTSFMRRQPVPMSV-ATTTTTKAFPSGF", 6, 39);
111
112     SequenceI hiddenSeq = new Sequence("FER_TOCH",
113             "FILGTMISKSFLFRKPAVTSL-KAISNVGE--ALF", 3, 34);
114     expectedHiddenSeqs[0] = hiddenSeq;
115
116     // create and add sequence features
117     SequenceFeature seqFeature2 = new SequenceFeature("feature_x",
118             "desciption", "status", 6, 15, "Jalview");
119     SequenceFeature seqFeature3 = new SequenceFeature("feature_x",
120             "desciption", "status", 9, 18, "Jalview");
121     SequenceFeature seqFeature4 = new SequenceFeature("feature_x",
122             "desciption", "status", 9, 18, "Jalview");
123     seqs[2].addSequenceFeature(seqFeature2);
124     seqs[3].addSequenceFeature(seqFeature3);
125     seqs[4].addSequenceFeature(seqFeature4);
126
127     for (Sequence seq : seqs)
128     {
129       seq.createDatasetSequence();
130       expectedSeqs.put(seq.getName(), seq);
131     }
132
133     // create and add sequence groups
134     ArrayList<SequenceI> grpSeqs = new ArrayList<SequenceI>();
135     grpSeqs.add(seqs[1]);
136     grpSeqs.add(seqs[2]);
137     grpSeqs.add(seqs[3]);
138     grpSeqs.add(seqs[4]);
139     SequenceGroup seqGrp = new SequenceGroup(grpSeqs, "JGroup:1883305585",
140             null, true, true, false, 21, 29);
141     ColourSchemeI scheme = ColourSchemeMapper.getJalviewColourScheme(
142             "zappo", seqGrp);
143     seqGrp.cs.setColourScheme(scheme);
144     seqGrp.setShowNonconserved(false);
145     seqGrp.setDescription(null);
146
147     expectedGrps.put(seqGrp.getName(), seqGrp);
148
149     // create and add annotation
150     Annotation[] annot = new Annotation[35];
151     annot[0] = new Annotation("", "", '\u0000', 0);
152     annot[1] = new Annotation("", "", '\u0000', 0);
153     annot[2] = new Annotation("α", "", 'H', 0);
154     annot[3] = new Annotation("α", "", 'H', 0);
155     annot[4] = new Annotation("α", "", 'H', 0);
156     annot[5] = new Annotation("", "", '\u0000', 0);
157     annot[6] = new Annotation("", "", '\u0000', 0);
158     annot[7] = new Annotation("", "", '\u0000', 0);
159     annot[8] = new Annotation("β", "", 'E', 0);
160     annot[9] = new Annotation("β", "", 'E', 0);
161     annot[10] = new Annotation("β", "", 'E', 0);
162     annot[11] = new Annotation("β", "", 'E', 0);
163     annot[12] = new Annotation("β", "", 'E', 0);
164     annot[13] = new Annotation("β", "", 'E', 0);
165     annot[14] = new Annotation("β", "", 'E', 0);
166     annot[15] = new Annotation("β", "", 'E', 0);
167     annot[16] = new Annotation("", "", '\u0000', 0);
168     annot[17] = new Annotation("", "", '\u0000', 0);
169     annot[18] = new Annotation("", "", '\u0000', 0);
170     annot[19] = new Annotation("", "", '\u0000', 0);
171     annot[20] = new Annotation("", "", '\u0000', 0);
172     annot[21] = new Annotation("", "", '\u0000', 0);
173     annot[22] = new Annotation("", "", '\u0000', 0);
174     annot[23] = new Annotation("", "", '\u0000', 0);
175     annot[24] = new Annotation("", "", '\u0000', 0);
176     annot[25] = new Annotation("", "", '\u0000', 0);
177     annot[26] = new Annotation("α", "", 'H', 0);
178     annot[27] = new Annotation("α", "", 'H', 0);
179     annot[28] = new Annotation("α", "", 'H', 0);
180     annot[29] = new Annotation("α", "", 'H', 0);
181     annot[30] = new Annotation("α", "", 'H', 0);
182     annot[31] = new Annotation("", "", '\u0000', 0);
183     annot[32] = new Annotation("", "", '\u0000', 0);
184     annot[33] = new Annotation("", "", '\u0000', 0);
185     annot[34] = new Annotation("", "", '\u0000', 0);
186
187     AlignmentAnnotation alignAnnot = new AlignmentAnnotation(
188             "Secondary Structure", "New description", annot);
189     expectedAnnots.put(alignAnnot.label, alignAnnot);
190
191     expectedColSel.hideColumns(32, 33);
192     expectedColSel.hideColumns(34, 34);
193
194     TEST_SEQ_HEIGHT = expectedSeqs.size();
195     TEST_GRP_HEIGHT = expectedGrps.size();
196     TEST_ANOT_HEIGHT = expectedAnnots.size();
197     TEST_CS_HEIGHT = expectedColSel.getHiddenColumns().size();
198
199     exportSettings = new AlignExportSettingI()
200     {
201       @Override
202       public boolean isExportHiddenSequences()
203       {
204         return true;
205       }
206
207       @Override
208       public boolean isExportHiddenColumns()
209       {
210         return true;
211       }
212
213       @Override
214       public boolean isExportGroups()
215       {
216         return true;
217       }
218
219       @Override
220       public boolean isExportFeatures()
221       {
222         return true;
223       }
224
225       @Override
226       public boolean isExportAnnotations()
227       {
228         return true;
229       }
230
231       @Override
232       public boolean isCancelled()
233       {
234         return false;
235       }
236     };
237
238     AppletFormatAdapter formatAdapter = new AppletFormatAdapter();
239     try
240     {
241       alignment = (Alignment) formatAdapter.readFile(TEST_JSON_FILE,
242               DataSourceType.FILE, FileFormat.Json);
243       jf = (JSONFile) formatAdapter.getAlignFile();
244
245       AlignFrame af = new AlignFrame(alignment, jf.getHiddenSequences(),
246               jf.getColumnSelection(), AlignFrame.DEFAULT_WIDTH,
247               AlignFrame.DEFAULT_HEIGHT);
248       af.getViewport().setShowSequenceFeatures(jf.isShowSeqFeatures());
249       String colourSchemeName = jf.getGlobalColourScheme();
250       ColourSchemeI cs = ColourSchemeMapper.getJalviewColourScheme(
251               colourSchemeName, alignment);
252       af.changeColour(cs);
253       af.getViewport().setFeaturesDisplayed(jf.getDisplayedFeatures());
254
255       formatAdapter = new AppletFormatAdapter(af.alignPanel, exportSettings);
256       String jsonOutput = formatAdapter.formatSequences(FileFormat.Json,
257               af.alignPanel.getAlignment(), false);
258
259       formatAdapter = new AppletFormatAdapter();
260       testAlignment = formatAdapter.readFile(jsonOutput,
261               DataSourceType.PASTE, FileFormat.Json);
262       testJsonFile = (JSONFile) formatAdapter.getAlignFile();
263       // System.out.println(jsonOutput);
264     } catch (IOException e)
265     {
266       e.printStackTrace();
267     }
268
269   }
270
271   @BeforeMethod(alwaysRun = true)
272   public void methodSetup()
273   {
274     passedCount = 0;
275   }
276
277   @AfterTest(alwaysRun = true)
278   public void tearDown() throws Exception
279   {
280     testJsonFile = null;
281     alignment = null;
282     expectedSeqs = null;
283     expectedAnnots = null;
284     expectedGrps = null;
285     testAlignment = null;
286     jf = null;
287   }
288
289   @Test(groups = { "Functional" })
290   public void roundTripTest()
291   {
292     assertNotNull("JSON roundtrip test failed!", testJsonFile);
293   }
294
295   @Test(groups = { "Functional" })
296   public void testSeqParsed()
297   {
298     assertNotNull("Couldn't read supplied alignment data.", testAlignment);
299     Assert.assertNotNull(testAlignment.getSequences());
300     for (SequenceI seq : testAlignment.getSequences())
301     {
302       SequenceI expectedSeq = expectedSeqs.get(seq.getName());
303       AssertJUnit.assertTrue(
304               "Failed Sequence Test  for >>> " + seq.getName(),
305               isSeqMatched(expectedSeq, seq));
306       passedCount++;
307     }
308     AssertJUnit.assertEquals("Some Sequences did not pass the test",
309             TEST_SEQ_HEIGHT, passedCount);
310   }
311
312   @Test(groups = { "Functional" })
313   public void hiddenColsTest()
314   {
315     ColumnSelection cs = testJsonFile.getColumnSelection();
316     Assert.assertNotNull(cs);
317     Assert.assertNotNull(cs.getHiddenColumns());
318     List<int[]> hiddenCols = cs.getHiddenColumns();
319     Assert.assertEquals(hiddenCols.size(), TEST_CS_HEIGHT);
320     Assert.assertEquals(hiddenCols.get(0), expectedColSel
321             .getHiddenColumns().get(0),
322             "Mismatched hidden columns!");
323   }
324
325   @Test(groups = { "Functional" })
326   public void hiddenSeqsTest()
327   {
328     Assert.assertNotNull(testJsonFile.getHiddenSequences(),
329             "Hidden sequence Expected but found Null");
330     Assert.assertEquals(jf.getHiddenSequences().length, 1,
331             "Hidden sequence");
332   }
333
334   @Test(groups = { "Functional" })
335   public void colorSchemeTest()
336   {
337     Assert.assertNotNull(testJsonFile.getGlobalColourScheme(),
338             "Colourscheme is null, parsing failed!");
339     Assert.assertEquals(testJsonFile.getGlobalColourScheme(), "Zappo",
340             "Zappo colour scheme expected!");
341   }
342
343   @Test(groups = { "Functional" })
344   /**
345    * Test for bug JAL-2489, NPE when exporting BioJSON with global colour scheme set as Null
346    */
347   public void testBioJSONRoundTripWithGlobalColourSchemeSetAsNone()
348   {
349     AppletFormatAdapter formatAdapter = new AppletFormatAdapter();
350
351     Alignment _alignment;
352     try
353     {
354       // load example BioJSON file
355       _alignment = (Alignment) formatAdapter.readFile(TEST_JSON_FILE,
356               DataSourceType.FILE, FileFormat.Json);
357       JSONFile bioJsonFile = (JSONFile) formatAdapter.getAlignFile();
358       AlignFrame alignFrame = new AlignFrame(_alignment,
359               bioJsonFile.getHiddenSequences(),
360               bioJsonFile.getColumnSelection(), AlignFrame.DEFAULT_WIDTH,
361               AlignFrame.DEFAULT_HEIGHT);
362       // Change colour scheme to 'None' and perform round trip
363       ColourSchemeI cs = ColourSchemeMapper.getJalviewColourScheme(
364               ResidueColourScheme.NONE, _alignment);
365       alignFrame.changeColour(cs);
366       alignFrame.getViewport().setFeaturesDisplayed(
367               bioJsonFile.getDisplayedFeatures());
368       formatAdapter = new AppletFormatAdapter(alignFrame.alignPanel,
369               exportSettings);
370       // export BioJSON string
371       String jsonOutput = formatAdapter.formatSequences(FileFormat.Json,
372               alignFrame.alignPanel.getAlignment(), false);
373       // read back Alignment from BioJSON string
374       formatAdapter = new AppletFormatAdapter();
375       formatAdapter.readFile(jsonOutput, DataSourceType.PASTE,
376               FileFormat.Json);
377       // assert 'None' colour scheme is retained after round trip
378       JSONFile _bioJsonFile = (JSONFile) formatAdapter.getAlignFile();
379       Assert.assertEquals(_bioJsonFile.getGlobalColourScheme(),
380               ResidueColourScheme.NONE);
381     } catch (IOException e)
382     {
383       e.printStackTrace();
384     }
385   }
386
387   @Test(groups = { "Functional" })
388   public void isShowSeqFeaturesSet()
389   {
390     Assert.assertTrue(testJsonFile.isShowSeqFeatures(),
391             "Sequence feature isDisplayed setting expected to be true");
392   }
393
394   @Test(groups = { "Functional" })
395   public void testGrpParsed()
396   {
397     Assert.assertNotNull(testAlignment.getGroups());
398     for (SequenceGroup seqGrp : testAlignment.getGroups())
399     {
400       SequenceGroup expectedGrp = expectedGrps.get(seqGrp.getName());
401       AssertJUnit.assertTrue(
402               "Failed SequenceGroup Test for >>> " + seqGrp.getName(),
403               isGroupMatched(expectedGrp, seqGrp));
404       passedCount++;
405     }
406     AssertJUnit.assertEquals("Some SequenceGroups did not pass the test",
407             TEST_GRP_HEIGHT, passedCount);
408   }
409
410   @Test(groups = { "Functional" })
411   public void testAnnotationParsed()
412   {
413     Assert.assertNotNull(testAlignment.getAlignmentAnnotation());
414     for (AlignmentAnnotation annot : testAlignment.getAlignmentAnnotation())
415     {
416       AlignmentAnnotation expectedAnnot = expectedAnnots.get(annot.label);
417       AssertJUnit.assertTrue("Failed AlignmentAnnotation Test for >>> "
418               + annot.label, isAnnotationMatched(expectedAnnot, annot));
419       passedCount++;
420     }
421     AssertJUnit.assertEquals("Some Sequences did not pass the test",
422             TEST_ANOT_HEIGHT, passedCount);
423   }
424
425   public boolean isAnnotationMatched(AlignmentAnnotation eAnnot,
426           AlignmentAnnotation annot)
427   {
428     if (!eAnnot.label.equals(annot.label)
429             || !eAnnot.description.equals(annot.description)
430             || eAnnot.annotations.length != annot.annotations.length)
431     {
432       return false;
433     }
434
435     for (int x = 0; x < annot.annotations.length; x++)
436     {
437       Annotation y = annot.annotations[x];
438       Annotation z = annot.annotations[x];
439
440       if (!y.displayCharacter.equals(z.displayCharacter)
441               || y.value != z.value
442               || y.secondaryStructure != z.secondaryStructure)
443       {
444         return false;
445       }
446     }
447     return true;
448   }
449
450   public boolean isSeqMatched(SequenceI expectedSeq, SequenceI actualSeq)
451   {
452     System.out.println("Testing >>> " + actualSeq.getName());
453
454     if (expectedSeq.getName().equals(actualSeq.getName())
455             && expectedSeq.getSequenceAsString().equals(
456                     actualSeq.getSequenceAsString())
457             && expectedSeq.getStart() == actualSeq.getStart()
458             && expectedSeq.getEnd() == actualSeq.getEnd()
459             && featuresMatched(expectedSeq, actualSeq))
460     {
461       return true;
462     }
463     return false;
464   }
465
466   public boolean isGroupMatched(SequenceGroup expectedGrp,
467           SequenceGroup actualGrp)
468   {
469
470     System.out.println("Testing >>> " + actualGrp.getName());
471     System.out.println(expectedGrp.getName() + " | " + actualGrp.getName());
472     System.out.println(expectedGrp.getColourText() + " | "
473             + actualGrp.getColourText());
474     System.out.println(expectedGrp.getDisplayBoxes() + " | "
475             + actualGrp.getDisplayBoxes());
476     System.out.println(expectedGrp.getIgnoreGapsConsensus() + " | "
477             + actualGrp.getIgnoreGapsConsensus());
478     System.out.println(expectedGrp.getSequences().size() + " | "
479             + actualGrp.getSequences().size());
480     System.out.println(expectedGrp.getStartRes() + " | "
481             + actualGrp.getStartRes());
482     System.out.println(expectedGrp.getEndRes() + " | "
483             + actualGrp.getEndRes());
484     System.out.println(expectedGrp.cs + " | " + actualGrp.cs);
485
486     if (expectedGrp.getName().equals(actualGrp.getName())
487             && expectedGrp.getColourText() == actualGrp.getColourText()
488             && expectedGrp.getDisplayBoxes() == actualGrp.getDisplayBoxes()
489             && expectedGrp.getIgnoreGapsConsensus() == actualGrp
490                     .getIgnoreGapsConsensus()
491             && (expectedGrp.cs.getClass().equals(actualGrp.cs.getClass()))
492             && expectedGrp.getSequences().size() == actualGrp
493                     .getSequences().size()
494             && expectedGrp.getStartRes() == actualGrp.getStartRes()
495             && expectedGrp.getEndRes() == actualGrp.getEndRes())
496     {
497       return true;
498     }
499     return false;
500   }
501
502   private boolean featuresMatched(SequenceI seq1, SequenceI seq2)
503   {
504     boolean matched = false;
505     try
506     {
507       if (seq1 == null && seq2 == null)
508       {
509         return true;
510       }
511
512       SequenceFeature[] inFeature = seq1.getSequenceFeatures();
513       SequenceFeature[] outFeature = seq2.getSequenceFeatures();
514
515       if (inFeature == null && outFeature == null)
516       {
517         return true;
518       }
519       else if ((inFeature == null && outFeature != null)
520               || (inFeature != null && outFeature == null))
521       {
522         return false;
523       }
524
525       int testSize = inFeature.length;
526       int matchedCount = 0;
527       for (SequenceFeature in : inFeature)
528       {
529         for (SequenceFeature out : outFeature)
530         {
531           System.out.println(out.getType() + " | " + in.getType());
532           System.out.println(out.getBegin() + " | " + in.getBegin());
533           System.out.println(out.getEnd() + " | " + in.getEnd());
534
535           if (inFeature.length == outFeature.length
536                   && in.getBegin() == out.getBegin()
537                   && in.getEnd() == out.getEnd()
538                   && in.getScore() == out.getScore()
539                   && in.getFeatureGroup().equals(out.getFeatureGroup())
540                   && in.getType().equals(out.getType()))
541           {
542
543             ++matchedCount;
544           }
545         }
546       }
547       System.out.println("matched count >>>>>> " + matchedCount);
548       if (testSize == matchedCount)
549       {
550         matched = true;
551       }
552     } catch (Exception e)
553     {
554       e.printStackTrace();
555     }
556     // System.out.println(">>>>>>>>>>>>>> features matched : " + matched);
557     return matched;
558   }
559 }