Merge branch 'bug/JAL-2154projectMappings' into merge/develop_bug/JAL-2154projectMappings
[jalview.git] / test / jalview / io / CrossRef2xmlTests.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 jalview.analysis.CrossRef;
24 import jalview.api.AlignmentViewPanel;
25 import jalview.datamodel.AlignedCodonFrame;
26 import jalview.datamodel.AlignmentI;
27 import jalview.datamodel.AlignmentTest;
28 import jalview.datamodel.SequenceI;
29 import jalview.gui.AlignFrame;
30 import jalview.gui.CrossRefAction;
31 import jalview.gui.Desktop;
32 import jalview.gui.Jalview2XML;
33
34 import java.io.File;
35 import java.io.IOException;
36 import java.util.ArrayList;
37 import java.util.HashMap;
38 import java.util.List;
39
40 import org.testng.Assert;
41 import org.testng.annotations.Test;
42
43 @Test(singleThreaded = true)
44 public class CrossRef2xmlTests extends Jalview2xmlBase
45 {
46
47   /**
48    * test store and recovery of expanded views
49    * 
50    * @throws Exception
51    */
52   @Test(groups = { "Operational" }, enabled = true)
53   public void testRetrieveAndShowCrossref() throws Exception
54   {
55
56     List<String> failedDBRetr = new ArrayList<String>();
57     List<String> failedXrefMenuItems = new ArrayList<String>();
58     List<String> failedProjectRecoveries = new ArrayList<String>();
59
60     // for every set of db queries
61     // retrieve db query
62     // verify presence of expected xrefs
63     // show xrefs - verify expected type of frame is shown for each xref
64     // show xrefs again
65     // - verify original -> xref -> xref(original) recovers frame containing at
66     // least the first retrieved sequence
67     // store
68     // 1. whole project
69     // 2. individual frames
70     // 3. load each one back and verify
71     // . aligned sequences (.toString() )
72     // . xrefs (.toString() )
73     // . codonframes
74     //
75     //
76     HashMap<String, String> dbtoviewBit = new HashMap<String, String>();
77     List<String> keyseq = new ArrayList<String>();
78     HashMap<String, File> savedProjects = new HashMap<String, File>();
79
80     for (String[] did : new String[][] { { "ENSEMBL", "ENSG00000157764" },
81     { "UNIPROT", "P01731" } })
82     {
83       // pass counters - 0 - first pass, 1 means retrieve project rather than
84       // perform action
85       int pass1 = 0, pass2 = 0, pass3 = 0;
86       // each do loop performs two iterations in the first outer loop pass, but
87       // only performs one iteration on the second outer loop
88       // ie. pass 1 = 0 {pass 2= 0 { pass 3 = 0,1 }, pass 2=1 { pass 3 = 0 }}, 1
89       // { pass 2 = 0 { pass 3 = 0 } }
90       do
91       {
92         String first = did[0] + " " + did[1];
93         AlignFrame af = null;
94         boolean dna;
95         AlignmentI retral;
96         AlignmentI dataset;
97         SequenceI[] seqs;
98         List<String> ptypes = null;
99         if (pass1 == 0)
100         {
101           // retrieve dbref
102
103           List<AlignFrame> afs = jalview.gui.SequenceFetcher.fetchAndShow(
104                   did[0], did[1]);
105           if (afs.size() == 0)
106           {
107             failedDBRetr.add("Didn't retrieve " + first);
108             break;
109           }
110           keyseq.add(first);
111           af = afs.get(0);
112
113           // verify references for retrieved data
114           AlignmentTest.assertAlignmentDatasetRefs(af.getViewport()
115                   .getAlignment(), "Pass (" + pass1 + "," + pass2 + ","
116                   + pass3 + "): Fetch " + first + ":");
117           dna = af.getViewport().getAlignment().isNucleotide();
118           retral = af.getViewport().getAlignment();
119           dataset = retral.getDataset();
120           seqs = retral.getSequencesArray();
121
122         }
123         else
124         {
125           Desktop.instance.closeAll_actionPerformed(null);
126           // recover stored project
127           af = new FileLoader(false).LoadFileWaitTillLoaded(savedProjects
128                   .get(first).toString(), FormatAdapter.FILE);
129           System.out.println("Recovered view for '" + first + "' from '"
130                   + savedProjects.get(first).toString() + "'");
131           dna = af.getViewport().getAlignment().isNucleotide();
132           retral = af.getViewport().getAlignment();
133           dataset = retral.getDataset();
134           seqs = retral.getSequencesArray();
135
136           // verify references for recovered data
137           AlignmentTest.assertAlignmentDatasetRefs(af.getViewport()
138                   .getAlignment(), "Pass (" + pass1 + "," + pass2 + ","
139                   + pass3 + "): Recover " + first + ":");
140
141         }
142
143         // store project on first pass, compare next pass
144         stringify(dbtoviewBit, savedProjects, first, af.alignPanel);
145
146         ptypes = (seqs == null || seqs.length == 0) ? null : new CrossRef(
147                 seqs, dataset).findXrefSourcesForSequences(dna);
148
149         // start of pass2: retrieve each cross-ref for fetched or restored
150         // project.
151         do // first cross ref and recover crossref loop
152         {
153
154           for (String db : ptypes)
155           {
156             // counter for splitframe views retrieved via crossref
157             int firstcr_ap = 0;
158             // build next key so we an retrieve all views
159             String nextxref = first + " -> " + db + "{" + firstcr_ap + "}";
160             // perform crossref action, or retrieve stored project
161             List<AlignmentViewPanel> cra_views = new ArrayList<AlignmentViewPanel>();
162             CrossRefAction cra = null;
163             
164             if (pass2 == 0)
165             { // retrieve and show cross-refs in this thread
166               cra = new CrossRefAction(af, seqs, dna, db);
167               cra.run();
168               if (cra.getXrefViews().size() == 0)
169               {
170                 failedXrefMenuItems.add("No crossrefs retrieved for "
171                         + first + " -> " + db);
172                 continue;
173               }
174               cra_views = cra.getXrefViews();
175               assertNucleotide(cra_views.get(0),
176                       "Nucleotide panel included proteins for " + first
177                               + " -> " + db);
178               assertProtein(cra_views.get(1),
179                       "Protein panel included nucleotides for " + first
180                               + " -> " + db);
181             }
182             else
183             {
184               Desktop.instance.closeAll_actionPerformed(null);
185               pass3 = 0;
186               // recover stored project
187               File storedProject = savedProjects.get(nextxref);
188               if (storedProject == null)
189               {
190                 failedProjectRecoveries.add("Failed to store a view for '"
191                         + nextxref + "'");
192                 continue;
193               }
194
195               // recover stored project
196               AlignFrame af2 = new FileLoader(false)
197                       .LoadFileWaitTillLoaded(savedProjects.get(nextxref)
198                               .toString(), FormatAdapter.FILE);
199               System.out.println("Recovered view for '" + nextxref
200                       + "' from '" + savedProjects.get(nextxref).toString()
201                       + "'");
202               // gymnastics to recover the alignPanel/Complementary alignPanel
203               if (af2.getViewport().isNucleotide())
204               {
205                 // top view, then bottom
206                 cra_views.add(af2.getViewport().getAlignPanel());
207                 cra_views.add(((jalview.gui.AlignViewport) af2
208                         .getViewport().getCodingComplement())
209                         .getAlignPanel());
210
211               }
212               else
213               {
214                 // bottom view, then top
215                 cra_views.add(((jalview.gui.AlignViewport) af2
216                         .getViewport().getCodingComplement())
217                         .getAlignPanel());
218                 cra_views.add(af2.getViewport().getAlignPanel());
219
220               }
221             }
222             HashMap<String, List<String>> xrptypes = new HashMap<String, List<String>>();
223             // first save/verify views.
224             for (AlignmentViewPanel avp : cra_views)
225             {
226               nextxref = first + " -> " + db + "{" + firstcr_ap++ + "}";
227               // verify references for this panel
228               AlignmentTest.assertAlignmentDatasetRefs(avp.getAlignment(),
229                       "Pass (" + pass1 + "," + pass2 + "," + pass3
230                               + "): before start of pass3: " + nextxref
231                               + ":");
232
233               SequenceI[] xrseqs = avp.getAlignment().getSequencesArray();
234
235               List<String> _xrptypes = (seqs == null || seqs.length == 0) ? null
236                       : new CrossRef(xrseqs, dataset)
237                               .findXrefSourcesForSequences(avp
238                                       .getAlignViewport().isNucleotide());
239               
240               stringify(dbtoviewBit, savedProjects, nextxref, avp);
241               xrptypes.put(nextxref, _xrptypes);
242
243             }
244
245             // now do the second xref pass starting from either saved or just
246             // recovered split pane, in sequence
247             do // retrieve second set of cross refs or recover and verify
248             {
249               firstcr_ap = 0;
250               for (AlignmentViewPanel avp : cra_views)
251               {
252                 nextxref = first + " -> " + db + "{" + firstcr_ap++ + "}";
253                 for (String xrefdb : xrptypes.get(nextxref))
254                 {
255                   List<AlignmentViewPanel> cra_views2 = new ArrayList<AlignmentViewPanel>();
256                   int q = 0;
257                   String nextnextxref = nextxref
258                           + " -> " + xrefdb + "{" + q + "}";
259
260                   if (pass3 == 0)
261                   {
262
263                     SequenceI[] xrseqs = avp.getAlignment()
264                             .getSequencesArray();
265                     AlignFrame nextaf = Desktop.getAlignFrameFor(avp
266                             .getAlignViewport());
267
268                     cra = new CrossRefAction(nextaf, xrseqs, avp
269                             .getAlignViewport().isNucleotide(), xrefdb);
270                     cra.run();
271                     if (cra.getXrefViews().size() == 0)
272                     {
273                       failedXrefMenuItems
274                               .add("No crossrefs retrieved for '"
275                               + nextxref + "' to " + xrefdb + " via '"
276                               + nextaf.getTitle() + "'");
277                       continue;
278                     }
279                     cra_views2 = cra.getXrefViews();
280                     assertNucleotide(cra_views2.get(0),
281                             "Nucleotide panel included proteins for '"
282                                     + nextxref + "' to " + xrefdb
283                                     + " via '" + nextaf.getTitle() + "'");
284                     assertProtein(cra_views2.get(1),
285                             "Protein panel included nucleotides for '"
286                                     + nextxref + "' to " + xrefdb
287                                     + " via '" + nextaf.getTitle() + "'");
288
289                   }
290                   else
291                   {
292                     Desktop.instance.closeAll_actionPerformed(null);
293                     // recover stored project
294                     File storedProject = savedProjects.get(nextnextxref);
295                     if (storedProject == null)
296                     {
297                       failedProjectRecoveries
298                               .add("Failed to store a view for '"
299                                       + nextnextxref + "'");
300                       continue;
301                     }
302                     AlignFrame af2 = new FileLoader(false)
303                             .LoadFileWaitTillLoaded(
304                                     savedProjects.get(nextnextxref)
305                                             .toString(), FormatAdapter.FILE);
306                     System.out.println("Recovered view for '"
307                             + nextnextxref + "' from '"
308                             + savedProjects.get(nextnextxref).toString()
309                             + "'");
310                     // gymnastics to recover the alignPanel/Complementary
311                     // alignPanel
312                     if (af2.getViewport().isNucleotide())
313                     {
314                       // top view, then bottom
315                       cra_views2.add(af2.getViewport().getAlignPanel());
316                       cra_views2.add(((jalview.gui.AlignViewport) af2
317                               .getViewport().getCodingComplement())
318                               .getAlignPanel());
319
320                     }
321                     else
322                     {
323                       // bottom view, then top
324                       cra_views2.add(((jalview.gui.AlignViewport) af2
325                               .getViewport().getCodingComplement())
326                               .getAlignPanel());
327                       cra_views2.add(af2.getViewport().getAlignPanel());
328                     }
329                     Assert.assertEquals(cra_views2.size(), 2);
330                     Assert.assertNotNull(cra_views2.get(0));
331                     Assert.assertNotNull(cra_views2.get(1));
332                   }
333
334                   for (AlignmentViewPanel nextavp : cra_views2)
335                   {
336                     nextnextxref = nextxref
337                             + " -> " + xrefdb + "{" + q++ + "}";
338
339                     // verify references for this panel
340                     AlignmentTest.assertAlignmentDatasetRefs(
341                             nextavp.getAlignment(), "" + "Pass (" + pass1
342                                     + "," + pass2 + "): For "
343                                     + nextnextxref + ":");
344
345                     stringify(dbtoviewBit, savedProjects, nextnextxref,
346                             nextavp);
347                     keyseq.add(nextnextxref);
348                   }
349                 } // end of loop around showing all xrefdb for crossrf2
350
351               } // end of loop around all viewpanels from crossrf1
352             } while (pass2 == 2 && pass3++ < 2);
353             // fetchdb->crossref1->crossref-2->verify for xrefs we
354             // either loop twice when pass2=0, or just once when pass2=1
355             // (recovered project from previous crossref)
356
357           } // end of loop over db-xrefs for crossref-2
358
359           // fetchdb-->crossref1
360           // for each xref we try to retrieve xref, store and verify when
361           // pass1=0, or just retrieve and verify when pass1=1
362         } while (pass1 == 1 && pass2++ < 2);
363         // fetchdb
364         // for each ref we
365         // loop twice: first, do the retrieve, second recover from saved project
366
367         // increment pass counters, so we repeat traversal starting from the
368         // oldest saved project first.
369         if (pass1 == 0)
370         {
371           // verify stored projects for first set of cross references
372           pass1 = 1;
373           // and verify cross-references retrieved from stored projects
374           pass2 = 0;
375           pass3 = 0;
376         }
377         else
378         {
379           pass1++;
380           if (pass1 < 2)
381           {
382             // verify stored projects for second set of cross references
383             pass2 = 1;
384           // and verify cross-references retrievable from those stored projects.
385             pass3 = 0;
386           }
387         }
388       } while (pass3 < 2);
389     }
390     if (failedXrefMenuItems.size() > 0)
391     {
392       for (String s : failedXrefMenuItems)
393       {
394         System.err.println(s);
395       }
396       Assert.fail("Faulty xref menu (" + failedXrefMenuItems.size()
397               + " counts)");
398     }
399     if (failedProjectRecoveries.size() > 0)
400     {
401
402       for (String s : failedProjectRecoveries)
403       {
404         System.err.println(s);
405       }
406       Assert.fail("Didn't recover projects for some retrievals (did they retrieve ?) ("
407               + failedProjectRecoveries.size() + " counts)");
408     }
409     if (failedDBRetr.size() > 0)
410     {
411       for (String s : failedProjectRecoveries)
412       {
413         System.err.println(s);
414       }
415       Assert.fail("Didn't retrieve some db refs for checking cross-refs ("
416               + failedDBRetr.size() + " counts)");
417     }
418   }
419
420   private void assertProtein(AlignmentViewPanel alignmentViewPanel,
421           String message)
422   {
423     assertType(true, alignmentViewPanel, message);
424   }
425
426   private void assertNucleotide(AlignmentViewPanel alignmentViewPanel,
427           String message)
428   {
429     assertType(false, alignmentViewPanel, message);
430   }
431
432   private void assertType(boolean expectProtein,
433           AlignmentViewPanel alignmentViewPanel, String message)
434   {
435     List<SequenceI> nonType = new ArrayList<SequenceI>();
436     for (SequenceI sq : alignmentViewPanel.getAlignViewport()
437             .getAlignment()
438             .getSequences())
439     {
440       if (sq.isProtein() != expectProtein)
441       {
442         nonType.add(sq);
443       }
444     }
445     if (nonType.size() > 0)
446     {
447       Assert.fail(message + " [ "
448               + (expectProtein ? "nucleotides were " : "proteins were ")
449               + nonType.toString()
450               + " ]");
451     }
452   }
453
454   /**
455    * first time called, record strings derived from alignment and
456    * alignedcodonframes, and save view to a project file. Second time called,
457    * compare strings to existing ones. org.testng.Assert.assertTrue on
458    * stringmatch
459    * 
460    * @param dbtoviewBit
461    *          map between xrefpath and view string
462    * @param savedProjects
463    *          - map from xrefpath to saved project filename (createTempFile)
464    * @param xrefpath
465    *          - xrefpath - unique ID for this context (composed of sequence of
466    *          db-fetch/cross-ref actions preceeding state)
467    * @param avp
468    *          - viewpanel to store (for viewpanels in splitframe, the same
469    *          project should be written for both panels, only one needs
470    *          recovering for comparison on the next stringify call, but each
471    *          viewpanel needs to be called with a distinct xrefpath to ensure
472    *          each one's strings are compared)
473    */
474   private void stringify(HashMap<String, String> dbtoviewBit,
475           HashMap<String, File> savedProjects, String xrefpath,
476           AlignmentViewPanel avp)
477   {
478     if (savedProjects != null)
479     {
480       if (savedProjects.get(xrefpath) == null)
481       {
482         // write a project file for this view. On the second pass, this will be
483         // recovered and cross-references verified
484         try
485         {
486           File prfile = File.createTempFile("crossRefTest", ".jvp");
487           AlignFrame af = Desktop.getAlignFrameFor(avp.getAlignViewport());
488           new Jalview2XML(false).saveAlignment(af, prfile.toString(),
489                   af.getTitle());
490           System.out.println("Written view from '" + xrefpath + "' as '"
491                   + prfile.getAbsolutePath() + "'");
492           savedProjects.put(xrefpath, prfile);
493         } catch (IOException q)
494         {
495           Assert.fail("Unexpected IO Exception", q);
496         }
497       }
498       else
499       {
500         System.out.println("Stringify check on view from '" + xrefpath
501                 + "' [ possibly retrieved from '"
502                 + savedProjects.get(xrefpath).getAbsolutePath() + "' ]");
503
504       }
505     }
506
507     StringBuilder sbr = new StringBuilder();
508     sbr.append(avp.getAlignment().toString());
509     sbr.append("\n");
510     sbr.append("<End of alignment>");
511     sbr.append("\n");
512     sbr.append(avp.getAlignment().getDataset());
513     sbr.append("\n");
514     sbr.append("<End of dataset>");
515     sbr.append("\n");
516     int p = 0;
517     if (avp.getAlignment().getCodonFrames() != null)
518     {
519       for (AlignedCodonFrame ac : avp.getAlignment().getCodonFrames())
520       {
521         sbr.append("<AlignedCodonFrame " + p++ + ">");
522         sbr.append("\n");
523         sbr.append(ac.toString());
524         sbr.append("\n");
525       }
526     }
527     String dbt = dbtoviewBit.get(xrefpath);
528     if (dbt == null)
529     {
530       dbtoviewBit.put(xrefpath, sbr.toString());
531     }
532     else
533     {
534       Assert.assertEquals(sbr.toString(), dbt, "stringify mismatch for "
535               + xrefpath);
536     }
537   }
538 }