846fa1aead98521e5265d93a37d4a357e125baa2
[jalview.git] / test / jalview / gui / StructureChooserTest.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.gui;
22
23 import static org.testng.Assert.assertEquals;
24 import static org.testng.AssertJUnit.assertNotNull;
25 import static org.testng.AssertJUnit.assertTrue;
26
27 import java.io.File;
28 import java.util.Collection;
29 import java.util.List;
30 import java.util.Vector;
31
32 import org.junit.Assert;
33 import org.testng.annotations.AfterMethod;
34 import org.testng.annotations.BeforeClass;
35 import org.testng.annotations.BeforeMethod;
36 import org.testng.annotations.DataProvider;
37 import org.testng.annotations.Test;
38
39 import jalview.api.AlignViewportI;
40 import jalview.bin.Cache;
41 import jalview.bin.Jalview;
42 import jalview.datamodel.AlignmentAnnotation;
43 import jalview.datamodel.AlignmentI;
44 import jalview.datamodel.DBRefEntry;
45 import jalview.datamodel.PDBEntry;
46 import jalview.datamodel.Sequence;
47 import jalview.datamodel.SequenceI;
48 import jalview.fts.api.FTSData;
49 import jalview.fts.core.FTSRestClient;
50 import jalview.fts.service.pdb.PDBFTSRestClient;
51 import jalview.fts.service.pdb.PDBFTSRestClientTest;
52 import jalview.fts.service.threedbeacons.TDBeaconsFTSRestClient;
53 import jalview.fts.threedbeacons.TDBeaconsFTSRestClientTest;
54 import jalview.gui.StructureViewer.ViewerType;
55 import jalview.gui.structurechooser.PDBStructureChooserQuerySource;
56 import jalview.io.DataSourceType;
57 import jalview.io.FileFormatException;
58 import jalview.io.FileFormatI;
59 import jalview.io.FileLoader;
60 import jalview.io.IdentifyFile;
61 import jalview.jbgui.FilterOption;
62 import jalview.structure.StructureImportSettings.TFType;
63 import junit.extensions.PA;
64
65 @Test(singleThreaded = true)
66 public class StructureChooserTest
67 {
68
69   @BeforeClass(alwaysRun = true)
70   public void setUpJvOptionPane()
71   {
72     JvOptionPane.setInteractiveMode(false);
73     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
74   }
75
76   Sequence seq, upSeq, upSeq_nocanonical;
77
78   @BeforeMethod(alwaysRun = true)
79   public void setUp() throws Exception
80   {
81     seq = new Sequence("PDB|4kqy|4KQY|A", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 1,
82             26);
83     seq.createDatasetSequence();
84     for (int x = 1; x < 5; x++)
85     {
86       DBRefEntry dbRef = new DBRefEntry();
87       dbRef.setAccessionId("XYZ_" + x);
88       seq.addDBRef(dbRef);
89     }
90
91     PDBEntry dbRef = new PDBEntry();
92     dbRef.setId("1tim");
93
94     Vector<PDBEntry> pdbIds = new Vector<>();
95     pdbIds.add(dbRef);
96
97     seq.setPDBId(pdbIds);
98
99     // Uniprot sequence for 3D-Beacons mocks
100     upSeq = new Sequence("P38398",
101             "MDLSALRVEEVQNVINAMQKILECPICLELIKEPVSTKCDHIFCKFCMLKLLNQKKGPSQCPLCKNDITKRS\n"
102                     + "LQESTRFSQLVEELLKIICAFQLDTGLEYANSYNFAKKENNSPEHLKDEVSIIQSMGYRNRAKRLLQSEPEN\n"
103                     + "PSLQETSLSVQLSNLGTVRTLRTKQRIQPQKTSVYIELGSDSSEDTVNKATYCSVGDQELLQITPQGTRDEI\n"
104                     + "SLDSAKKAACEFSETDVTNTEHHQPSNNDLNTTEKRAAERHPEKYQGSSVSNLHVEPCGTNTHASSLQHENS\n"
105                     + "SLLLTKDRMNVEKAEFCNKSKQPGLARSQHNRWAGSKETCNDRRTPSTEKKVDLNADPLCERKEWNKQKLPC\n"
106                     + "SENPRDTEDVPWITLNSSIQKVNEWFSRSDELLGSDDSHDGESESNAKVADVLDVLNEVDEYSGSSEKIDLL\n"
107                     + "ASDPHEALICKSERVHSKSVESNIEDKIFGKTYRKKASLPNLSHVTENLIIGAFVTEPQIIQERPLTNKLKR\n"
108                     + "KRRPTSGLHPEDFIKKADLAVQKTPEMINQGTNQTEQNGQVMNITNSGHENKTKGDSIQNEKNPNPIESLEK\n"
109                     + "ESAFKTKAEPISSSISNMELELNIHNSKAPKKNRLRRKSSTRHIHALELVVSRNLSPPNCTELQIDSCSSSE\n"
110                     + "EIKKKKYNQMPVRHSRNLQLMEGKEPATGAKKSNKPNEQTSKRHDSDTFPELKLTNAPGSFTKCSNTSELKE\n"
111                     + "FVNPSLPREEKEEKLETVKVSNNAEDPKDLMLSGERVLQTERSVESSSISLVPGTDYGTQESISLLEVSTLG\n"
112                     + "KAKTEPNKCVSQCAAFENPKGLIHGCSKDNRNDTEGFKYPLGHEVNHSRETSIEMEESELDAQYLQNTFKVS\n"
113                     + "KRQSFAPFSNPGNAEEECATFSAHSGSLKKQSPKVTFECEQKEENQGKNESNIKPVQTVNITAGFPVVGQKD\n"
114                     + "KPVDNAKCSIKGGSRFCLSSQFRGNETGLITPNKHGLLQNPYRIPPLFPIKSFVKTKCKKNLLEENFEEHSM\n"
115                     + "SPEREMGNENIPSTVSTISRNNIRENVFKEASSSNINEVGSSTNEVGSSINEIGSSDENIQAELGRNRGPKL\n"
116                     + "NAMLRLGVLQPEVYKQSLPGSNCKHPEIKKQEYEEVVQTVNTDFSPYLISDNLEQPMGSSHASQVCSETPDD\n"
117                     + "LLDDGEIKEDTSFAENDIKESSAVFSKSVQKGELSRSPSPFTHTHLAQGYRRGAKKLESSEENLSSEDEELP\n"
118                     + "CFQHLLFGKVNNIPSQSTRHSTVATECLSKNTEENLLSLKNSLNDCSNQVILAKASQEHHLSEETKCSASLF\n"
119                     + "SSQCSELEDLTANTNTQDPFLIGSSKQMRHQSESQGVGLSDKELVSDDEERGTGLEENNQEEQSMDSNLGEA\n"
120                     + "ASGCESETSVSEDCSGLSSQSDILTTQQRDTMQHNLIKLQQEMAELEAVLEQHGSQPSNSYPSIISDSSALE\n"
121                     + "DLRNPEQSTSEKAVLTSQKSSEYPISQNPEGLSADKFEVSADSSTSKNKEPGVERSSPSKCPSLDDRWYMHS\n"
122                     + "CSGSLQNRNYPSQEELIKVVDVEEQQLEESGPHDLTETSYLPRQDLEGTPYLESGISLFSDDPESDPSEDRA\n"
123                     + "PESARVGNIPSSTSALKVPQLKVAESAQSPAAAHTTDTAGYNAMEESVSREKPELTASTERVNKRMSMVVSG\n"
124                     + "LTPEEFMLVYKFARKHHITLTNLITEETTHVVMKTDAEFVCERTLKYFLGIAGGKWVVSYFWVTQSIKERKM\n"
125                     + "LNEHDFEVRGDVVNGRNHQGPKRARESQDRKIFRGLEICCYGPFTNMPTDQLEWMVQLCGASVVKELSSFTL\n"
126                     + "GTGVHPIVVVQPDAWTEDNGFHAIGQMCEAPVVTREWVLDSVALYQCQELDTYLIPQIPHSHY\n"
127                     + "",
128             1, 1863);
129     upSeq.setDescription("Breast cancer type 1 susceptibility protein");
130     upSeq_nocanonical = new Sequence(upSeq);
131     upSeq.createDatasetSequence();
132     upSeq.addDBRef(new DBRefEntry("UNIPROT", "0", "P38398", null, true));
133
134     upSeq_nocanonical.createDatasetSequence();
135     // not a canonical reference
136     upSeq_nocanonical.addDBRef(
137             new DBRefEntry("UNIPROT", "0", "P38398", null, false));
138
139   }
140
141   @AfterMethod(alwaysRun = true)
142   public void tearDown() throws Exception
143   {
144     seq = null;
145     upSeq = null;
146     upSeq_nocanonical = null;
147   }
148
149   @Test(groups = { "Functional" })
150   public void populateFilterComboBoxTest() throws InterruptedException
151   {
152     TDBeaconsFTSRestClientTest.setMock();
153     PDBFTSRestClientTest.setMock();
154
155     SequenceI[] selectedSeqs = new SequenceI[] { seq };
156     StructureChooser sc = new StructureChooser(selectedSeqs, seq, null);
157     ThreadwaitFor(200, sc);
158
159     // if structures are not discovered then don't
160     // populate filter options
161     sc.populateFilterComboBox(false, false);
162     int optionsSize = sc.getCmbFilterOption().getItemCount();
163     System.out.println("Items (no data, no cache): ");
164     StringBuilder items = new StringBuilder();
165     for (int p = 0; p < optionsSize; p++)
166     {
167       items.append("- ")
168               .append(sc.getCmbFilterOption().getItemAt(p).getName())
169               .append("\n");
170
171     }
172     // report items when this fails - seems to be a race condition
173     Assert.assertEquals(items.toString(), optionsSize, 2);
174
175     sc.populateFilterComboBox(true, false);
176     optionsSize = sc.getCmbFilterOption().getItemCount();
177     assertTrue(optionsSize > 3); // if structures are found, filter options
178                                  // should be populated
179
180     sc.populateFilterComboBox(true, true);
181     assertTrue(sc.getCmbFilterOption().getSelectedItem() != null);
182     FilterOption filterOpt = (FilterOption) sc.getCmbFilterOption()
183             .getSelectedItem();
184     assertEquals("Cached Structures", filterOpt.getName());
185     FTSRestClient
186             .unMock((FTSRestClient) TDBeaconsFTSRestClient.getInstance());
187     FTSRestClient.unMock((FTSRestClient) PDBFTSRestClient.getInstance());
188
189   }
190
191   @Test(groups = { "Functional" })
192   public void displayTDBQueryTest() throws InterruptedException
193   {
194     TDBeaconsFTSRestClientTest.setMock();
195     PDBFTSRestClientTest.setMock();
196
197     SequenceI[] selectedSeqs = new SequenceI[] { upSeq_nocanonical };
198     StructureChooser sc = new StructureChooser(selectedSeqs,
199             upSeq_nocanonical, null);
200     // mock so should be quick. Exceptions from mocked PDBFTS are expected too
201     ThreadwaitFor(500, sc);
202
203     assertTrue(sc.isCanQueryTDB() && sc.isNotQueriedTDBYet());
204   }
205
206   @Test(groups = { "Network" })
207   public void fetchStructuresInfoTest()
208   {
209     FTSRestClient
210             .unMock((FTSRestClient) TDBeaconsFTSRestClient.getInstance());
211     PDBFTSRestClient.unMock((FTSRestClient) PDBFTSRestClient.getInstance());
212     SequenceI[] selectedSeqs = new SequenceI[] { seq };
213     StructureChooser sc = new StructureChooser(selectedSeqs, seq, null);
214     // not mocked, wait for 2s
215     ThreadwaitFor(2000, sc);
216
217     sc.fetchStructuresMetaData();
218     Collection<FTSData> ss = (Collection<FTSData>) PA.getValue(sc,
219             "discoveredStructuresSet");
220     assertNotNull(ss);
221     assertTrue(ss.size() > 0);
222   }
223
224   @Test(groups = { "Functional" })
225   public void fetchStructuresInfoMockedTest()
226   {
227     TDBeaconsFTSRestClientTest.setMock();
228     PDBFTSRestClientTest.setMock();
229     SequenceI[] selectedSeqs = new SequenceI[] { upSeq };
230     StructureChooser sc = new StructureChooser(selectedSeqs, seq, null);
231     ThreadwaitFor(500, sc);
232
233     sc.fetchStructuresMetaData();
234     Collection<FTSData> ss = (Collection<FTSData>) PA.getValue(sc,
235             "discoveredStructuresSet");
236     assertNotNull(ss);
237     assertTrue(ss.size() > 0);
238     
239     sc.promptForTDBFetch(true);
240     try {
241       Thread.sleep(500);
242     } catch (Exception q) {}
243     
244     // check collation
245     Object[] sqandpdb = sc.collectSelectedSeqsAndPDBEntries();
246     assertNotNull(sqandpdb);
247     SequenceI[] selsq = (SequenceI[]) sqandpdb[0];
248     PDBEntry[] selpdb = (PDBEntry[]) sqandpdb[1];
249     assertNotNull(selsq);
250     assertNotNull(selpdb);
251     assertEquals(1, selsq.length);
252     assertEquals(1, selpdb.length);
253     assertTrue(selpdb[0].hasProvider());
254     assertTrue(selpdb[0].hasTempFacType());
255     
256     
257   }
258
259   private void ThreadwaitFor(int i, StructureChooser sc)
260   {
261     long timeout = i + System.currentTimeMillis();
262     while (!sc.isDialogVisible() && timeout > System.currentTimeMillis())
263     {
264       try
265       {
266         Thread.sleep(50);
267       } catch (InterruptedException x)
268       {
269
270       }
271     }
272
273   }
274
275   @Test(groups = { "Functional" })
276   public void sanitizeSeqNameTest()
277   {
278     String name = "ab_cdEF|fwxyz012349";
279     assertEquals(name,
280             PDBStructureChooserQuerySource.sanitizeSeqName(name));
281
282     // remove a [nn] substring
283     name = "abcde12[345]fg";
284     assertEquals("abcde12fg",
285             PDBStructureChooserQuerySource.sanitizeSeqName(name));
286
287     // remove characters other than a-zA-Z0-9 | or _
288     name = "ab[cd],.\t£$*!- \\\"@:e";
289     assertEquals("abcde",
290             PDBStructureChooserQuerySource.sanitizeSeqName(name));
291
292     name = "abcde12[345a]fg";
293     assertEquals("abcde12345afg",
294             PDBStructureChooserQuerySource.sanitizeSeqName(name));
295   }
296
297   @Test(groups = { "Functional" }, dataProvider = "openStructureFileParams")
298   public void openStructureFileForSequenceTest(String alfile, String seqid,
299           String sFilename, TFType tft, String paeFilename,
300           boolean showRefAnnotations, boolean doXferSettings,
301           ViewerType viewerType, int seqNum, int annNum, int viewerNum,
302           String propsFile)
303   {
304     Cache.loadProperties(
305             propsFile == null ? "test/jalview/io/testProps.jvprops"
306                     : propsFile);
307
308     Jalview.main(
309             propsFile == null ? null : new String[]
310             { "--props", propsFile });
311     if (Desktop.instance != null)
312       Desktop.instance.closeAll_actionPerformed(null);
313     JvOptionPane.setInteractiveMode(false);
314     JvOptionPane.setMockResponse(JvOptionPane.OK_OPTION);
315
316     FileLoader fileLoader = new FileLoader(true);
317     FileFormatI format = null;
318     File alFile = new File(alfile);
319     try
320     {
321       format = new IdentifyFile().identify(alFile, DataSourceType.FILE);
322     } catch (FileFormatException e1)
323     {
324       Assert.fail(
325               "Unknown file format for '" + alFile.getAbsolutePath() + "'");
326     }
327
328     AlignFrame af = fileLoader.LoadFileWaitTillLoaded(alFile,
329             DataSourceType.FILE, format);
330     AlignmentPanel ap = af.alignPanel;
331     Assert.assertNotNull("No alignPanel", ap);
332
333     AlignmentI al = ap.getAlignment();
334     Assert.assertNotNull(al);
335
336     SequenceI seq = al.findName(seqid);
337     Assert.assertNotNull("Sequence '" + seqid + "' not found in alignment",
338             seq);
339
340     StructureChooser.openStructureFileForSequence(null, null, ap, seq,
341             false, sFilename, tft, paeFilename, false, showRefAnnotations,
342             doXferSettings, viewerType);
343
344     List<SequenceI> seqs = al.getSequences();
345     Assert.assertNotNull(seqs);
346
347     Assert.assertEquals("Wrong number of sequences", seqNum, seqs.size());
348
349     AlignViewportI av = ap.getAlignViewport();
350     Assert.assertNotNull(av);
351
352     AlignmentAnnotation[] aas = al.getAlignmentAnnotation();
353     int visibleAnn = 0;
354     for (AlignmentAnnotation aa : aas)
355     {
356       if (aa.visible)
357         visibleAnn++;
358     }
359     Assert.assertEquals("Wrong number of viewed annotations", annNum,
360             visibleAnn);
361
362     if (viewerNum > -1)
363     {
364       try
365       {
366         Thread.sleep(100);
367       } catch (InterruptedException e)
368       {
369         // TODO Auto-generated catch block
370         e.printStackTrace();
371       }
372       List<StructureViewerBase> openViewers = Desktop.instance
373               .getStructureViewers(ap, null);
374       Assert.assertNotNull(openViewers);
375       int count = 0;
376       for (StructureViewerBase svb : openViewers)
377       {
378         if (svb.isVisible())
379           count++;
380       }
381       Assert.assertEquals("Wrong number of structure viewers opened",
382               viewerNum, count);
383
384     }
385
386     if (af != null)
387     {
388       af.setVisible(false);
389       af.dispose();
390     }
391   }
392
393   @DataProvider(name = "openStructureFileParams")
394   public Object[][] openStructureFileParams()
395   {
396     /*
397         String alFile,
398         String seqid,
399         String structureFilename,
400         TFType tft,
401         String paeFilename,
402         boolean showRefAnnotations,
403         boolean doXferSettings, // false for Commands
404         ViewerType viewerType,
405         int seqNum,
406         int annNum,
407         int viewerNum,
408         String propsFile
409      */
410     return new Object[][] {
411         /*
412         */
413         { "examples/uniref50.fa", "FER1_SPIOL",
414             "examples/AlphaFold/AF-P00221-F1-model_v4.cif", TFType.DEFAULT,
415             "examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json",
416             true, false, null, 15, 7, 0, null },
417         { "examples/uniref50.fa", "FER1_SPIOL",
418             "examples/AlphaFold/AF-P00221-F1-model_v4.cif", TFType.PLDDT,
419             "examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json",
420             true, false, null, 15, 7, 0, null },
421         { "examples/uniref50.fa", "FER1_SPIOL",
422             "examples/AlphaFold/AF-P00221-F1-model_v4.cif", TFType.PLDDT,
423             "examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json",
424             false, false, null, 15, 4, 0, null },
425         { "examples/uniref50.fa", "FER1_SPIOL",
426             "examples/AlphaFold/AF-P00221-F1-model_v4.cif", TFType.DEFAULT,
427             "examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json",
428             true, false, ViewerType.JMOL, 15, 7, 1, null },
429         { "examples/uniref50.fa", "FER1_SPIOL",
430             "examples/AlphaFold/AF-P00221-F1-model_v4.cif", TFType.PLDDT,
431             "examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json",
432             true, false, ViewerType.JMOL, 15, 7, 1, null },
433         { "examples/uniref50.fa", "FER1_SPIOL",
434             "examples/AlphaFold/AF-P00221-F1-model_v4.cif", TFType.PLDDT,
435             "examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json",
436             false, false, ViewerType.JMOL, 15, 4, 1, null }, };
437   }
438
439 }