JAL-2246 basic sanity test of fetching example accessions
[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 a sequence group
134     List<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,
140             "JGroup:1883305585",
141             null, true, true, false, 21, 29);
142     ColourSchemeI scheme = ColourSchemeMapper.getJalviewColourScheme(
143             "zappo", seqGrp);
144     seqGrp.cs.setColourScheme(scheme);
145     seqGrp.setShowNonconserved(false);
146     seqGrp.setDescription(null);
147
148     expectedGrps.put(seqGrp.getName(), seqGrp);
149
150     // create and add annotation
151     Annotation[] annot = new Annotation[35];
152     annot[0] = new Annotation("", "", '\u0000', 0);
153     annot[1] = new Annotation("", "", '\u0000', 0);
154     annot[2] = new Annotation("α", "", 'H', 0);
155     annot[3] = new Annotation("α", "", 'H', 0);
156     annot[4] = new Annotation("α", "", 'H', 0);
157     annot[5] = new Annotation("", "", '\u0000', 0);
158     annot[6] = new Annotation("", "", '\u0000', 0);
159     annot[7] = new Annotation("", "", '\u0000', 0);
160     annot[8] = new Annotation("β", "", 'E', 0);
161     annot[9] = new Annotation("β", "", 'E', 0);
162     annot[10] = new Annotation("β", "", 'E', 0);
163     annot[11] = new Annotation("β", "", 'E', 0);
164     annot[12] = new Annotation("β", "", 'E', 0);
165     annot[13] = new Annotation("β", "", 'E', 0);
166     annot[14] = new Annotation("β", "", 'E', 0);
167     annot[15] = new Annotation("β", "", 'E', 0);
168     annot[16] = new Annotation("", "", '\u0000', 0);
169     annot[17] = new Annotation("", "", '\u0000', 0);
170     annot[18] = new Annotation("", "", '\u0000', 0);
171     annot[19] = new Annotation("", "", '\u0000', 0);
172     annot[20] = new Annotation("", "", '\u0000', 0);
173     annot[21] = new Annotation("", "", '\u0000', 0);
174     annot[22] = new Annotation("", "", '\u0000', 0);
175     annot[23] = new Annotation("", "", '\u0000', 0);
176     annot[24] = new Annotation("", "", '\u0000', 0);
177     annot[25] = new Annotation("", "", '\u0000', 0);
178     annot[26] = new Annotation("α", "", 'H', 0);
179     annot[27] = new Annotation("α", "", 'H', 0);
180     annot[28] = new Annotation("α", "", 'H', 0);
181     annot[29] = new Annotation("α", "", 'H', 0);
182     annot[30] = new Annotation("α", "", 'H', 0);
183     annot[31] = new Annotation("", "", '\u0000', 0);
184     annot[32] = new Annotation("", "", '\u0000', 0);
185     annot[33] = new Annotation("", "", '\u0000', 0);
186     annot[34] = new Annotation("", "", '\u0000', 0);
187
188     AlignmentAnnotation alignAnnot = new AlignmentAnnotation(
189             "Secondary Structure", "New description", annot);
190     expectedAnnots.put(alignAnnot.label, alignAnnot);
191
192     expectedColSel.hideColumns(32, 33);
193     expectedColSel.hideColumns(34, 34);
194
195     TEST_SEQ_HEIGHT = expectedSeqs.size();
196     TEST_GRP_HEIGHT = expectedGrps.size();
197     TEST_ANOT_HEIGHT = expectedAnnots.size();
198     TEST_CS_HEIGHT = expectedColSel.getHiddenColumns().size();
199
200     exportSettings = new AlignExportSettingI()
201     {
202       @Override
203       public boolean isExportHiddenSequences()
204       {
205         return true;
206       }
207
208       @Override
209       public boolean isExportHiddenColumns()
210       {
211         return true;
212       }
213
214       @Override
215       public boolean isExportGroups()
216       {
217         return true;
218       }
219
220       @Override
221       public boolean isExportFeatures()
222       {
223         return true;
224       }
225
226       @Override
227       public boolean isExportAnnotations()
228       {
229         return true;
230       }
231
232       @Override
233       public boolean isCancelled()
234       {
235         return false;
236       }
237     };
238
239     AppletFormatAdapter formatAdapter = new AppletFormatAdapter();
240     try
241     {
242       alignment = (Alignment) formatAdapter.readFile(TEST_JSON_FILE,
243               DataSourceType.FILE, FileFormat.Json);
244       jf = (JSONFile) formatAdapter.getAlignFile();
245
246       AlignFrame af = new AlignFrame(alignment, jf.getHiddenSequences(),
247               jf.getColumnSelection(), AlignFrame.DEFAULT_WIDTH,
248               AlignFrame.DEFAULT_HEIGHT);
249       af.getViewport().setShowSequenceFeatures(jf.isShowSeqFeatures());
250       String colourSchemeName = jf.getGlobalColourScheme();
251       ColourSchemeI cs = ColourSchemeMapper.getJalviewColourScheme(
252               colourSchemeName, alignment);
253       af.changeColour(cs);
254       af.getViewport().setFeaturesDisplayed(jf.getDisplayedFeatures());
255
256       formatAdapter = new AppletFormatAdapter(af.alignPanel, exportSettings);
257       String jsonOutput = formatAdapter.formatSequences(FileFormat.Json,
258               af.alignPanel.getAlignment(), false);
259
260       formatAdapter = new AppletFormatAdapter();
261       testAlignment = formatAdapter.readFile(jsonOutput,
262               DataSourceType.PASTE, FileFormat.Json);
263       testJsonFile = (JSONFile) formatAdapter.getAlignFile();
264       // System.out.println(jsonOutput);
265     } catch (IOException e)
266     {
267       e.printStackTrace();
268     }
269
270   }
271
272   @BeforeMethod(alwaysRun = true)
273   public void methodSetup()
274   {
275     passedCount = 0;
276   }
277
278   @AfterTest(alwaysRun = true)
279   public void tearDown() throws Exception
280   {
281     testJsonFile = null;
282     alignment = null;
283     expectedSeqs = null;
284     expectedAnnots = null;
285     expectedGrps = null;
286     testAlignment = null;
287     jf = null;
288   }
289
290   @Test(groups = { "Functional" })
291   public void roundTripTest()
292   {
293     assertNotNull("JSON roundtrip test failed!", testJsonFile);
294   }
295
296   @Test(groups = { "Functional" })
297   public void testSeqParsed()
298   {
299     assertNotNull("Couldn't read supplied alignment data.", testAlignment);
300     Assert.assertNotNull(testAlignment.getSequences());
301     for (SequenceI seq : testAlignment.getSequences())
302     {
303       SequenceI expectedSeq = expectedSeqs.get(seq.getName());
304       AssertJUnit.assertTrue(
305               "Failed Sequence Test  for >>> " + seq.getName(),
306               isSeqMatched(expectedSeq, seq));
307       passedCount++;
308     }
309     AssertJUnit.assertEquals("Some Sequences did not pass the test",
310             TEST_SEQ_HEIGHT, passedCount);
311   }
312
313   @Test(groups = { "Functional" })
314   public void hiddenColsTest()
315   {
316     ColumnSelection cs = testJsonFile.getColumnSelection();
317     Assert.assertNotNull(cs);
318     Assert.assertNotNull(cs.getHiddenColumns());
319     List<int[]> hiddenCols = cs.getHiddenColumns();
320     Assert.assertEquals(hiddenCols.size(), TEST_CS_HEIGHT);
321     Assert.assertEquals(hiddenCols.get(0), expectedColSel
322             .getHiddenColumns().get(0),
323             "Mismatched hidden columns!");
324   }
325
326   @Test(groups = { "Functional" })
327   public void hiddenSeqsTest()
328   {
329     Assert.assertNotNull(testJsonFile.getHiddenSequences(),
330             "Hidden sequence Expected but found Null");
331     Assert.assertEquals(jf.getHiddenSequences().length, 1,
332             "Hidden sequence");
333   }
334
335   @Test(groups = { "Functional" })
336   public void colorSchemeTest()
337   {
338     Assert.assertNotNull(testJsonFile.getGlobalColourScheme(),
339             "Colourscheme is null, parsing failed!");
340     Assert.assertEquals(testJsonFile.getGlobalColourScheme(), "Zappo",
341             "Zappo colour scheme expected!");
342   }
343
344   /**
345    * Test for bug JAL-2489, NPE when exporting BioJSON with global colour
346    * scheme, and a group colour scheme, set as 'None'
347    */
348   @Test(groups = { "Functional" })
349   public void testBioJSONRoundTripWithColourSchemeNone()
350   {
351     AppletFormatAdapter formatAdapter = new AppletFormatAdapter();
352
353     Alignment _alignment;
354     try
355     {
356       // load example BioJSON file
357       _alignment = (Alignment) formatAdapter.readFile(TEST_JSON_FILE,
358               DataSourceType.FILE, FileFormat.Json);
359       JSONFile bioJsonFile = (JSONFile) formatAdapter.getAlignFile();
360       AlignFrame alignFrame = new AlignFrame(_alignment,
361               bioJsonFile.getHiddenSequences(),
362               bioJsonFile.getColumnSelection(), AlignFrame.DEFAULT_WIDTH,
363               AlignFrame.DEFAULT_HEIGHT);
364
365       /*
366        * Create a group on the alignment;
367        * Change global and group colour scheme to 'None' and perform round trip
368        */
369       SequenceGroup sg = new SequenceGroup();
370       sg.addSequence(_alignment.getSequenceAt(0), false);
371       sg.setColourScheme(null);
372       ColourSchemeI cs = ColourSchemeMapper.getJalviewColourScheme(
373               ResidueColourScheme.NONE, _alignment);
374       alignFrame.changeColour(cs);
375       alignFrame.getViewport().setFeaturesDisplayed(
376               bioJsonFile.getDisplayedFeatures());
377       formatAdapter = new AppletFormatAdapter(alignFrame.alignPanel,
378               exportSettings);
379       // export BioJSON string
380       String jsonOutput = formatAdapter.formatSequences(FileFormat.Json,
381               alignFrame.alignPanel.getAlignment(), false);
382       // read back Alignment from BioJSON string
383       formatAdapter = new AppletFormatAdapter();
384       formatAdapter.readFile(jsonOutput, DataSourceType.PASTE,
385               FileFormat.Json);
386       // assert 'None' colour scheme is retained after round trip
387       JSONFile _bioJsonFile = (JSONFile) formatAdapter.getAlignFile();
388       Assert.assertEquals(_bioJsonFile.getGlobalColourScheme(),
389               ResidueColourScheme.NONE);
390     } catch (IOException e)
391     {
392       e.printStackTrace();
393     }
394   }
395
396   @Test(groups = { "Functional" })
397   public void isShowSeqFeaturesSet()
398   {
399     Assert.assertTrue(testJsonFile.isShowSeqFeatures(),
400             "Sequence feature isDisplayed setting expected to be true");
401   }
402
403   @Test(groups = { "Functional" })
404   public void testGrpParsed()
405   {
406     Assert.assertNotNull(testAlignment.getGroups());
407     for (SequenceGroup seqGrp : testAlignment.getGroups())
408     {
409       SequenceGroup expectedGrp = expectedGrps.get(seqGrp.getName());
410       AssertJUnit.assertTrue(
411               "Failed SequenceGroup Test for >>> " + seqGrp.getName(),
412               isGroupMatched(expectedGrp, seqGrp));
413       passedCount++;
414     }
415     AssertJUnit.assertEquals("Some SequenceGroups did not pass the test",
416             TEST_GRP_HEIGHT, passedCount);
417   }
418
419   @Test(groups = { "Functional" })
420   public void testAnnotationParsed()
421   {
422     Assert.assertNotNull(testAlignment.getAlignmentAnnotation());
423     for (AlignmentAnnotation annot : testAlignment.getAlignmentAnnotation())
424     {
425       AlignmentAnnotation expectedAnnot = expectedAnnots.get(annot.label);
426       AssertJUnit.assertTrue("Failed AlignmentAnnotation Test for >>> "
427               + annot.label, isAnnotationMatched(expectedAnnot, annot));
428       passedCount++;
429     }
430     AssertJUnit.assertEquals("Some Sequences did not pass the test",
431             TEST_ANOT_HEIGHT, passedCount);
432   }
433
434   public boolean isAnnotationMatched(AlignmentAnnotation eAnnot,
435           AlignmentAnnotation annot)
436   {
437     if (!eAnnot.label.equals(annot.label)
438             || !eAnnot.description.equals(annot.description)
439             || eAnnot.annotations.length != annot.annotations.length)
440     {
441       return false;
442     }
443
444     for (int x = 0; x < annot.annotations.length; x++)
445     {
446       Annotation y = annot.annotations[x];
447       Annotation z = annot.annotations[x];
448
449       if (!y.displayCharacter.equals(z.displayCharacter)
450               || y.value != z.value
451               || y.secondaryStructure != z.secondaryStructure)
452       {
453         return false;
454       }
455     }
456     return true;
457   }
458
459   public boolean isSeqMatched(SequenceI expectedSeq, SequenceI actualSeq)
460   {
461     System.out.println("Testing >>> " + actualSeq.getName());
462
463     if (expectedSeq.getName().equals(actualSeq.getName())
464             && expectedSeq.getSequenceAsString().equals(
465                     actualSeq.getSequenceAsString())
466             && expectedSeq.getStart() == actualSeq.getStart()
467             && expectedSeq.getEnd() == actualSeq.getEnd()
468             && featuresMatched(expectedSeq, actualSeq))
469     {
470       return true;
471     }
472     return false;
473   }
474
475   public boolean isGroupMatched(SequenceGroup expectedGrp,
476           SequenceGroup actualGrp)
477   {
478
479     System.out.println("Testing >>> " + actualGrp.getName());
480     System.out.println(expectedGrp.getName() + " | " + actualGrp.getName());
481     System.out.println(expectedGrp.getColourText() + " | "
482             + actualGrp.getColourText());
483     System.out.println(expectedGrp.getDisplayBoxes() + " | "
484             + actualGrp.getDisplayBoxes());
485     System.out.println(expectedGrp.getIgnoreGapsConsensus() + " | "
486             + actualGrp.getIgnoreGapsConsensus());
487     System.out.println(expectedGrp.getSequences().size() + " | "
488             + actualGrp.getSequences().size());
489     System.out.println(expectedGrp.getStartRes() + " | "
490             + actualGrp.getStartRes());
491     System.out.println(expectedGrp.getEndRes() + " | "
492             + actualGrp.getEndRes());
493     System.out.println(expectedGrp.cs + " | " + actualGrp.cs);
494
495     if (expectedGrp.getName().equals(actualGrp.getName())
496             && expectedGrp.getColourText() == actualGrp.getColourText()
497             && expectedGrp.getDisplayBoxes() == actualGrp.getDisplayBoxes()
498             && expectedGrp.getIgnoreGapsConsensus() == actualGrp
499                     .getIgnoreGapsConsensus()
500             && (expectedGrp.cs.getClass().equals(actualGrp.cs.getClass()))
501             && expectedGrp.getSequences().size() == actualGrp
502                     .getSequences().size()
503             && expectedGrp.getStartRes() == actualGrp.getStartRes()
504             && expectedGrp.getEndRes() == actualGrp.getEndRes())
505     {
506       return true;
507     }
508     return false;
509   }
510
511   private boolean featuresMatched(SequenceI seq1, SequenceI seq2)
512   {
513     boolean matched = false;
514     try
515     {
516       if (seq1 == null && seq2 == null)
517       {
518         return true;
519       }
520
521       SequenceFeature[] inFeature = seq1.getSequenceFeatures();
522       SequenceFeature[] outFeature = seq2.getSequenceFeatures();
523
524       if (inFeature == null && outFeature == null)
525       {
526         return true;
527       }
528       else if ((inFeature == null && outFeature != null)
529               || (inFeature != null && outFeature == null))
530       {
531         return false;
532       }
533
534       int testSize = inFeature.length;
535       int matchedCount = 0;
536       for (SequenceFeature in : inFeature)
537       {
538         for (SequenceFeature out : outFeature)
539         {
540           System.out.println(out.getType() + " | " + in.getType());
541           System.out.println(out.getBegin() + " | " + in.getBegin());
542           System.out.println(out.getEnd() + " | " + in.getEnd());
543
544           if (inFeature.length == outFeature.length
545                   && in.getBegin() == out.getBegin()
546                   && in.getEnd() == out.getEnd()
547                   && in.getScore() == out.getScore()
548                   && in.getFeatureGroup().equals(out.getFeatureGroup())
549                   && in.getType().equals(out.getType()))
550           {
551
552             ++matchedCount;
553           }
554         }
555       }
556       System.out.println("matched count >>>>>> " + matchedCount);
557       if (testSize == matchedCount)
558       {
559         matched = true;
560       }
561     } catch (Exception e)
562     {
563       e.printStackTrace();
564     }
565     // System.out.println(">>>>>>>>>>>>>> features matched : " + matched);
566     return matched;
567   }
568
569   /**
570    * Test group roundtrip with null (None) group colour scheme
571    * 
572    * @throws IOException
573    */
574   @Test(groups = { "Functional" })
575   public void testGrpParsed_colourNone() throws IOException
576   {
577     AlignmentI copy = new Alignment(testAlignment);
578     SequenceGroup sg = testAlignment.getGroups().get(0);
579     SequenceGroup copySg = new SequenceGroup(new ArrayList<SequenceI>(),
580             sg.getName(),
581             null, sg.getDisplayBoxes(), sg.getDisplayText(),
582             sg.getColourText(), sg.getStartRes(), sg.getEndRes());
583     for (SequenceI seq : sg.getSequences())
584     {
585       int seqIndex = testAlignment.findIndex(seq);
586       copySg.addSequence(copy.getSequenceAt(seqIndex), false);
587     }
588     copy.addGroup(copySg);
589
590     AlignFrame af = new AlignFrame(copy, copy.getWidth(), copy.getHeight());
591     AppletFormatAdapter formatAdapter = new AppletFormatAdapter(
592             af.alignPanel);
593     String jsonOutput = formatAdapter.formatSequences(FileFormat.Json,
594             copy, false);
595     formatAdapter = new AppletFormatAdapter();
596     AlignmentI newAlignment = formatAdapter.readFile(jsonOutput,
597             DataSourceType.PASTE, FileFormat.Json);
598
599     Assert.assertNotNull(newAlignment.getGroups());
600     for (SequenceGroup seqGrp : newAlignment.getGroups())
601     {
602       SequenceGroup expectedGrp = expectedGrps.get(seqGrp.getName());
603       AssertJUnit.assertTrue(
604               "Failed SequenceGroup Test for >>> " + seqGrp.getName(),
605               isGroupMatched(expectedGrp, seqGrp));
606       passedCount++;
607     }
608     AssertJUnit.assertEquals("Some SequenceGroups did not pass the test",
609             TEST_GRP_HEIGHT, passedCount);
610   }
611 }