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.Assert.assertEquals;
24 import static org.testng.Assert.assertNotNull;
25 import static org.testng.Assert.assertTrue;
27 import jalview.analysis.CrossRef;
28 import jalview.api.AlignmentViewPanel;
29 import jalview.datamodel.AlignedCodonFrame;
30 import jalview.datamodel.AlignmentI;
31 import jalview.datamodel.AlignmentTest;
32 import jalview.datamodel.SequenceI;
33 import jalview.gui.AlignFrame;
34 import jalview.gui.CrossRefAction;
35 import jalview.gui.Desktop;
36 import jalview.gui.JvOptionPane;
37 import jalview.gui.SequenceFetcher;
38 import jalview.project.Jalview2XML;
39 import jalview.util.DBRefUtils;
42 import java.io.IOException;
43 import java.util.ArrayList;
44 import java.util.Arrays;
45 import java.util.HashMap;
46 import java.util.List;
49 import org.testng.Assert;
50 import org.testng.annotations.BeforeClass;
51 import org.testng.annotations.DataProvider;
52 import org.testng.annotations.Test;
54 import junit.extensions.PA;
56 @Test(singleThreaded = true)
57 public class CrossRef2xmlTests extends Jalview2xmlBase
61 @BeforeClass(alwaysRun = true)
62 public void setUpJvOptionPane()
64 JvOptionPane.setInteractiveMode(false);
65 JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
68 @Test(groups = { "Functional" }, enabled = true)
69 public void openCrossrefsForEnsemblTwice()
71 AlignFrame af = new FileLoader(false).LoadFileWaitTillLoaded(
72 "examples/testdata/CantShowEnsemblCrossrefsTwice.jvp",
74 assertNotNull(af, "Couldn't load test's project.");
75 AlignmentI origAlig = af.getViewport().getAlignment();
76 List<String> source = new CrossRef(origAlig.getSequencesArray(),
77 origAlig.getDataset()).findXrefSourcesForSequences(true);
78 assertEquals(source.size(), 1, "Expected just one crossref to show.");
79 List<AlignmentViewPanel> views;
81 // try to show once - in a code block so handler is forgotten about
82 CrossRefAction xref1 = CrossRefAction.getHandlerFor(
83 origAlig.getSequencesArray(), true, source.get(0), af);
87 views = (List<AlignmentViewPanel>) PA.getValue(xref1, "xrefViews");
88 assertTrue(views.size() > 0,
89 "Couldn't get cross ref on first attempt (SERIOUS FAIL).");
90 } catch (Exception ex)
92 Assert.fail("Unexpected Exception for first xref action", ex);
97 // now just try it again
98 CrossRefAction xref2 = CrossRefAction.getHandlerFor(
99 origAlig.getSequencesArray(), true, source.get(0), af);
103 views = (List<AlignmentViewPanel>) PA.getValue(xref2, "xrefViews");
104 assertTrue(views.size() > 0,
105 "Couldn't get cross ref on second attempt (SERIOUS FAIL).");
106 } catch (Exception ex)
108 Assert.fail("Unexpected Exception for second xref action", ex);
110 // TODO : check that both views contain the same data
113 @DataProvider(name = "initialAccessions")
114 static Object[][] getAccessions()
116 return new String[][] { { "UNIPROT", "P00338" },
117 { "UNIPROT", "Q8Z9G6" },
118 { "ENSEMBLGENOMES", "CAD01290" } };
122 * test store and recovery of all reachable cross refs from all reachable
123 * crossrefs for one or more fetched db refs. Currently, this test has a known
131 dataProvider = "initialAccessions",
133 public void testRetrieveAndShowCrossref(String forSource,
134 String forAccession) throws Exception
137 List<String> failedDBRetr = new ArrayList<>();
138 List<String> failedXrefMenuItems = new ArrayList<>();
139 List<String> failedProjectRecoveries = new ArrayList<>();
140 // only search for ensembl or Uniprot crossrefs
141 List<String> limit = Arrays
143 { DBRefUtils.getCanonicalName("ENSEMBL"),
144 DBRefUtils.getCanonicalName("Uniprot") });
145 // for every set of db queries
147 // verify presence of expected xrefs
148 // show xrefs - verify expected type of frame is shown for each xref
150 // - verify original -> xref -> xref(original) recovers frame containing at
151 // least the first retrieved sequence
154 // 2. individual frames
155 // 3. load each one back and verify
156 // . aligned sequences (.toString() )
157 // . xrefs (.toString() )
161 Map<String, String> dbtoviewBit = new HashMap<>();
162 List<String> keyseq = new ArrayList<>();
163 Map<String, File> savedProjects = new HashMap<>();
165 // for (String[] did : new String[][] { { "UNIPROT", "P00338" } })
167 // pass counters - 0 - first pass, 1 means retrieve project rather than
169 int pass1 = 0, pass2 = 0, pass3 = 0;
170 // each do loop performs two iterations in the first outer loop pass, but
171 // only performs one iteration on the second outer loop
172 // ie. pass 1 = 0 {pass 2= 0 { pass 3 = 0,1 }, pass 2=1 { pass 3 = 0 }}, 1
173 // { pass 2 = 0 { pass 3 = 0 } }
176 String first = forSource + " " + forAccession;// did[0] + " " + did[1];
177 AlignFrame af = null;
182 List<String> ptypes = null;
187 SequenceFetcher sf = new SequenceFetcher(Desktop.instance,
188 forSource, forAccession);
190 AlignFrame[] afs = Desktop.getAlignFrames();
193 failedDBRetr.add("Didn't retrieve " + first);
199 // verify references for retrieved data
200 AlignmentTest.assertAlignmentDatasetRefs(
201 af.getViewport().getAlignment(), "Pass (" + pass1 + ","
202 + pass2 + "," + pass3 + "): Fetch " + first + ":");
203 assertDatasetIsNormalisedKnownDefect(
204 af.getViewport().getAlignment(), "Pass (" + pass1 + ","
205 + pass2 + "," + pass3 + "): Fetch " + first + ":");
206 dna = af.getViewport().getAlignment().isNucleotide();
207 retral = af.getViewport().getAlignment();
208 dataset = retral.getDataset();
209 seqs = retral.getSequencesArray();
214 Desktop.instance.closeAll_actionPerformed(null);
215 // recover stored project
216 af = new FileLoader(false).LoadFileWaitTillLoaded(
217 savedProjects.get(first).toString(), DataSourceType.FILE);
218 System.out.println("Recovered view for '" + first + "' from '"
219 + savedProjects.get(first).toString() + "'");
220 dna = af.getViewport().getAlignment().isNucleotide();
221 retral = af.getViewport().getAlignment();
222 dataset = retral.getDataset();
223 seqs = retral.getSequencesArray();
225 // verify references for recovered data
226 AlignmentTest.assertAlignmentDatasetRefs(
227 af.getViewport().getAlignment(),
228 "Pass (" + pass1 + "," + pass2 + "," + pass3 + "): Recover "
230 assertDatasetIsNormalisedKnownDefect(
231 af.getViewport().getAlignment(),
232 "Pass (" + pass1 + "," + pass2 + "," + pass3 + "): Recover "
237 // store project on first pass, compare next pass
238 stringify(dbtoviewBit, savedProjects, first, af.alignPanel);
240 ptypes = (seqs == null || seqs.length == 0) ? null
241 : new CrossRef(seqs, dataset)
242 .findXrefSourcesForSequences(dna);
243 filterDbRefs(ptypes, limit);
245 // start of pass2: retrieve each cross-ref for fetched or restored
247 do // first cross ref and recover crossref loop
250 for (String db : ptypes)
252 // counter for splitframe views retrieved via crossref
254 // build next key so we an retrieve all views
255 String nextxref = first + " -> " + db + "{" + firstcr_ap + "}";
256 // perform crossref action, or retrieve stored project
257 List<AlignmentViewPanel> cra_views = new ArrayList<>();
258 CrossRefAction cra = null;
261 { // retrieve and show cross-refs in this thread
262 cra = CrossRefAction.getHandlerFor(seqs, dna, db, af);
264 cra_views = (List<AlignmentViewPanel>) PA.getValue(cra,
266 if (cra_views.size() == 0)
268 failedXrefMenuItems.add(
269 "No crossrefs retrieved for " + first + " -> " + db);
272 assertNucleotide(cra_views.get(0),
273 "Nucleotide panel included proteins for " + first
275 assertProtein(cra_views.get(1),
276 "Protein panel included nucleotides for " + first
281 Desktop.instance.closeAll_actionPerformed(null);
283 // recover stored project
284 File storedProject = savedProjects.get(nextxref);
285 if (storedProject == null)
287 failedProjectRecoveries
288 .add("Failed to store a view for '" + nextxref + "'");
292 // recover stored project
293 AlignFrame af2 = new FileLoader(false).LoadFileWaitTillLoaded(
294 savedProjects.get(nextxref).toString(),
295 DataSourceType.FILE);
297 .println("Recovered view for '" + nextxref + "' from '"
298 + savedProjects.get(nextxref).toString() + "'");
299 // gymnastics to recover the alignPanel/Complementary alignPanel
300 if (af2.getViewport().isNucleotide())
302 // top view, then bottom
303 cra_views.add(af2.getViewport().getAlignPanel());
304 cra_views.add(((jalview.gui.AlignViewport) af2.getViewport()
305 .getCodingComplement()).getAlignPanel());
310 // bottom view, then top
311 cra_views.add(((jalview.gui.AlignViewport) af2.getViewport()
312 .getCodingComplement()).getAlignPanel());
313 cra_views.add(af2.getViewport().getAlignPanel());
317 HashMap<String, List<String>> xrptypes = new HashMap<>();
318 // first save/verify views.
319 for (AlignmentViewPanel avp : cra_views)
321 nextxref = first + " -> " + db + "{" + firstcr_ap++ + "}";
322 // verify references for this panel
323 AlignmentTest.assertAlignmentDatasetRefs(avp.getAlignment(),
324 "Pass (" + pass1 + "," + pass2 + "," + pass3
325 + "): before start of pass3: " + nextxref
327 assertDatasetIsNormalisedKnownDefect(avp.getAlignment(),
328 "Pass (" + pass1 + "," + pass2 + "," + pass3
329 + "): before start of pass3: " + nextxref
332 SequenceI[] xrseqs = avp.getAlignment().getSequencesArray();
334 List<String> _xrptypes = (seqs == null || seqs.length == 0)
336 : new CrossRef(xrseqs, dataset)
337 .findXrefSourcesForSequences(
338 avp.getAlignViewport().isNucleotide());
340 stringify(dbtoviewBit, savedProjects, nextxref, avp);
341 xrptypes.put(nextxref, _xrptypes);
345 // now do the second xref pass starting from either saved or just
346 // recovered split pane, in sequence
347 do // retrieve second set of cross refs or recover and verify
350 for (AlignmentViewPanel avp : cra_views)
352 nextxref = first + " -> " + db + "{" + firstcr_ap++ + "}";
353 for (String xrefdb : xrptypes.get(nextxref))
355 List<AlignmentViewPanel> cra_views2 = new ArrayList<>();
357 String nextnextxref = nextxref + " -> " + xrefdb + "{" + q
362 SequenceI[] xrseqs = avp.getAlignment()
363 .getSequencesArray();
364 AlignFrame nextaf = Desktop
365 .getAlignFrameFor(avp.getAlignViewport());
367 cra = CrossRefAction.getHandlerFor(xrseqs,
368 avp.getAlignViewport().isNucleotide(), xrefdb,
371 cra_views2 = (List<AlignmentViewPanel>) PA.getValue(cra,
373 if (cra_views2.size() == 0)
375 failedXrefMenuItems.add("No crossrefs retrieved for '"
376 + nextxref + "' to " + xrefdb + " via '"
377 + nextaf.getTitle() + "'");
380 assertNucleotide(cra_views2.get(0),
381 "Nucleotide panel included proteins for '"
382 + nextxref + "' to " + xrefdb + " via '"
383 + nextaf.getTitle() + "'");
384 assertProtein(cra_views2.get(1),
385 "Protein panel included nucleotides for '"
386 + nextxref + "' to " + xrefdb + " via '"
387 + nextaf.getTitle() + "'");
392 Desktop.instance.closeAll_actionPerformed(null);
393 // recover stored project
394 File storedProject = savedProjects.get(nextnextxref);
395 if (storedProject == null)
397 failedProjectRecoveries
398 .add("Failed to store a view for '"
399 + nextnextxref + "'");
402 AlignFrame af2 = new FileLoader(false)
403 .LoadFileWaitTillLoaded(savedProjects
404 .get(nextnextxref).toString(),
405 DataSourceType.FILE);
407 .println("Recovered view for '" + nextnextxref
408 + "' from '" + savedProjects
409 .get(nextnextxref).toString()
411 // gymnastics to recover the alignPanel/Complementary
413 if (af2.getViewport().isNucleotide())
415 // top view, then bottom
416 cra_views2.add(af2.getViewport().getAlignPanel());
417 cra_views2.add(((jalview.gui.AlignViewport) af2
418 .getViewport().getCodingComplement())
424 // bottom view, then top
425 cra_views2.add(((jalview.gui.AlignViewport) af2
426 .getViewport().getCodingComplement())
428 cra_views2.add(af2.getViewport().getAlignPanel());
430 Assert.assertEquals(cra_views2.size(), 2);
431 Assert.assertNotNull(cra_views2.get(0));
432 Assert.assertNotNull(cra_views2.get(1));
435 for (AlignmentViewPanel nextavp : cra_views2)
437 nextnextxref = nextxref + " -> " + xrefdb + "{" + q++
440 // verify references for this panel
441 AlignmentTest.assertAlignmentDatasetRefs(
442 nextavp.getAlignment(),
443 "" + "Pass (" + pass1 + "," + pass2 + "): For "
444 + nextnextxref + ":");
445 assertDatasetIsNormalisedKnownDefect(
446 nextavp.getAlignment(),
447 "" + "Pass (" + pass1 + "," + pass2 + "): For "
448 + nextnextxref + ":");
450 stringify(dbtoviewBit, savedProjects, nextnextxref,
452 keyseq.add(nextnextxref);
454 } // end of loop around showing all xrefdb for crossrf2
456 } // end of loop around all viewpanels from crossrf1
457 } while (pass2 == 2 && pass3++ < 2);
458 // fetchdb->crossref1->crossref-2->verify for xrefs we
459 // either loop twice when pass2=0, or just once when pass2=1
460 // (recovered project from previous crossref)
462 } // end of loop over db-xrefs for crossref-2
464 // fetchdb-->crossref1
465 // for each xref we try to retrieve xref, store and verify when
466 // pass1=0, or just retrieve and verify when pass1=1
467 } while (pass1 == 1 && pass2++ < 2);
470 // loop twice: first, do the retrieve, second recover from saved project
472 // increment pass counters, so we repeat traversal starting from the
473 // oldest saved project first.
476 // verify stored projects for first set of cross references
478 // and verify cross-references retrieved from stored projects
488 if (failedXrefMenuItems.size() > 0)
490 for (String s : failedXrefMenuItems)
492 System.err.println(s);
494 Assert.fail("Faulty xref menu (" + failedXrefMenuItems.size()
497 if (failedProjectRecoveries.size() > 0)
500 for (String s : failedProjectRecoveries)
502 System.err.println(s);
505 "Didn't recover projects for some retrievals (did they retrieve ?) ("
506 + failedProjectRecoveries.size() + " counts)");
508 if (failedDBRetr.size() > 0)
510 for (String s : failedProjectRecoveries)
512 System.err.println(s);
514 Assert.fail("Didn't retrieve some db refs for checking cross-refs ("
515 + failedDBRetr.size() + " counts)");
519 private void filterDbRefs(List<String> ptypes, List<String> limit)
524 while (ptypes.size() > p)
526 if (!limit.contains(ptypes.get(p)))
539 * wrapper to trap known defect for AH002001 testcase
544 private void assertDatasetIsNormalisedKnownDefect(AlignmentI al,
549 AlignmentTest.assertDatasetIsNormalised(al, message);
550 } catch (AssertionError ae)
552 if (!ae.getMessage().endsWith("EMBL|AH002001"))
558 System.out.println("Ignored exception for known defect: JAL-2179 : "
565 private void assertProtein(AlignmentViewPanel alignmentViewPanel,
568 assertType(true, alignmentViewPanel, message);
571 private void assertNucleotide(AlignmentViewPanel alignmentViewPanel,
574 assertType(false, alignmentViewPanel, message);
577 private void assertType(boolean expectProtein,
578 AlignmentViewPanel alignmentViewPanel, String message)
580 List<SequenceI> nonType = new ArrayList<>();
581 for (SequenceI sq : alignmentViewPanel.getAlignViewport().getAlignment()
584 if (sq.isProtein() != expectProtein)
589 if (nonType.size() > 0)
591 Assert.fail(message + " [ "
592 + (expectProtein ? "nucleotides were " : "proteins were ")
593 + nonType.toString() + " ]");
598 * first time called, record strings derived from alignment and
599 * alignedcodonframes, and save view to a project file. Second time called,
600 * compare strings to existing ones. org.testng.Assert.assertTrue on
604 * map between xrefpath and view string
605 * @param savedProjects
606 * - map from xrefpath to saved project filename (createTempFile)
608 * - xrefpath - unique ID for this context (composed of sequence of
609 * db-fetch/cross-ref actions preceeding state)
611 * - viewpanel to store (for viewpanels in splitframe, the same
612 * project should be written for both panels, only one needs
613 * recovering for comparison on the next stringify call, but each
614 * viewpanel needs to be called with a distinct xrefpath to ensure
615 * each one's strings are compared)
617 private void stringify(Map<String, String> dbtoviewBit,
618 Map<String, File> savedProjects, String xrefpath,
619 AlignmentViewPanel avp)
621 if (savedProjects != null)
623 if (savedProjects.get(xrefpath) == null)
625 // write a project file for this view. On the second pass, this will be
626 // recovered and cross-references verified
629 File prfile = File.createTempFile("crossRefTest", ".jvp");
630 AlignFrame af = Desktop.getAlignFrameFor(avp.getAlignViewport());
631 new Jalview2XML(false).saveAlignment(af, prfile.toString(),
633 System.out.println("Written view from '" + xrefpath + "' as '"
634 + prfile.getAbsolutePath() + "'");
635 savedProjects.put(xrefpath, prfile);
636 } catch (IOException q)
638 Assert.fail("Unexpected IO Exception", q);
643 System.out.println("Stringify check on view from '" + xrefpath
644 + "' [ possibly retrieved from '"
645 + savedProjects.get(xrefpath).getAbsolutePath() + "' ]");
650 StringBuilder sbr = new StringBuilder();
651 sbr.append(avp.getAlignment().toString());
653 sbr.append("<End of alignment>");
655 sbr.append(avp.getAlignment().getDataset());
657 sbr.append("<End of dataset>");
660 if (avp.getAlignment().getCodonFrames() != null)
662 for (AlignedCodonFrame ac : avp.getAlignment().getCodonFrames())
664 sbr.append("<AlignedCodonFrame " + p++ + ">");
666 sbr.append(ac.toString());
670 String dbt = dbtoviewBit.get(xrefpath);
673 dbtoviewBit.put(xrefpath, sbr.toString());
677 Assert.assertEquals(sbr.toString(), dbt,
678 "stringify mismatch for " + xrefpath);