99ec9a6bcd08d7791c59a6e7fbb905c07f5df490
[jalview.git] / test / jalview / io / ScoreMatrixFileTest.java
1 package jalview.io;
2
3 import static org.testng.Assert.assertEquals;
4 import static org.testng.Assert.assertFalse;
5 import static org.testng.Assert.assertNotNull;
6 import static org.testng.Assert.assertNull;
7 import static org.testng.Assert.assertTrue;
8 import static org.testng.Assert.fail;
9
10 import jalview.analysis.scoremodels.ScoreMatrix;
11 import jalview.analysis.scoremodels.ScoreModels;
12
13 import java.io.IOException;
14 import java.net.MalformedURLException;
15
16 import org.testng.annotations.AfterMethod;
17 import org.testng.annotations.Test;
18
19 public class ScoreMatrixFileTest
20 {
21
22   @AfterMethod(alwaysRun = true)
23   public void tearDownAfterTest()
24   {
25     ScoreModels.getInstance().reset();
26   }
27
28   /**
29    * Test a successful parse of a (small) score matrix file
30    * 
31    * @throws IOException
32    * @throws MalformedURLException
33    */
34   @Test(groups = "Functional")
35   public void testParseMatrix_ncbiMixedDelimiters()
36           throws MalformedURLException, IOException
37   {
38     /*
39      * some messy but valid input data, with comma, space
40      * or tab (or combinations) as score value delimiters
41      * this example includes 'guide' symbols on score rows
42      */
43     String data = "ScoreMatrix MyTest (example)\n" + "A\tT\tU\tt\tx\t-\n"
44             + "A,1.1,1.2,1.3,1.4, 1.5, 1.6\n"
45             + "T,2.1 2.2 2.3 2.4 2.5 2.6\n"
46             + "U\t3.1\t3.2\t3.3\t3.4\t3.5\t3.6\t\n"
47             + "t, 5.1,5.3,5.3,5.4,5.5, 5.6\n"
48             + "x\t6.1, 6.2 6.3 6.4 6.5 6.6\n"
49             + "-, \t7.1\t7.2 7.3, 7.4, 7.5\t,7.6\n";
50     FileParse fp = new FileParse(data, DataSourceType.PASTE);
51     ScoreMatrixFile parser = new ScoreMatrixFile(fp);
52     ScoreMatrix sm = parser.parseMatrix();
53
54     assertNotNull(sm);
55     assertEquals(sm.getName(), "MyTest (example)");
56     assertEquals(sm.getSize(), 6);
57     assertNull(sm.getDescription());
58     assertTrue(sm.isDNA());
59     assertFalse(sm.isProtein());
60     assertEquals(sm.getMinimumScore(), 1.1f);
61     assertEquals(sm.getPairwiseScore('A', 'A'), 1.1f);
62     assertEquals(sm.getPairwiseScore('A', 'T'), 1.2f);
63     assertEquals(sm.getPairwiseScore('a', 'T'), 1.2f); // A/a equivalent
64     assertEquals(sm.getPairwiseScore('A', 't'), 1.4f); // T/t not equivalent
65     assertEquals(sm.getPairwiseScore('a', 't'), 1.4f);
66     assertEquals(sm.getPairwiseScore('U', 'x'), 3.5f);
67     assertEquals(sm.getPairwiseScore('u', 'x'), 3.5f);
68     // X (upper) and '.' unmapped - get minimum score
69     assertEquals(sm.getPairwiseScore('U', 'X'), 1.1f);
70     assertEquals(sm.getPairwiseScore('A', '.'), 1.1f);
71     assertEquals(sm.getPairwiseScore('-', '-'), 7.6f);
72     assertEquals(sm.getPairwiseScore('A', (char) 128), 0f); // out of range
73   }
74
75   @Test(groups = "Functional")
76   public void testParseMatrix_headerMissing()
77   {
78     String data;
79
80     data = "X Y\n1 2\n3 4\n";
81     try
82     {
83       new ScoreMatrixFile(new FileParse(data, DataSourceType.PASTE))
84               .parseMatrix();
85       fail("expected exception");
86     } catch (IOException e)
87     {
88       assertEquals(e.getMessage(),
89               "Format error: 'ScoreMatrix <name>' should be the first non-comment line");
90     }
91   }
92
93   @Test(groups = "Functional")
94   public void testParseMatrix_ncbiNotEnoughRows()
95   {
96     String data = "ScoreMatrix MyTest\nX Y Z\n1 2 3\n4 5 6\n";
97     try
98     {
99       new ScoreMatrixFile(new FileParse(data, DataSourceType.PASTE))
100               .parseMatrix();
101       fail("expected exception");
102     } catch (IOException e)
103     {
104       assertEquals(e.getMessage(),
105               "Expected 3 rows of score data in score matrix but only found 2");
106     }
107   }
108
109   @Test(groups = "Functional")
110   public void testParseMatrix_ncbiNotEnoughColumns()
111   {
112     String data = "ScoreMatrix MyTest\nX Y Z\n1 2 3\n4 5\n7 8 9\n";
113     try
114     {
115       new ScoreMatrixFile(new FileParse(data, DataSourceType.PASTE))
116               .parseMatrix();
117       fail("expected exception");
118     } catch (IOException e)
119     {
120       assertEquals(e.getMessage(),
121               "Expected 3 scores at line 4: '4 5' but found 2");
122     }
123   }
124
125   @Test(groups = "Functional")
126   public void testParseMatrix_ncbiTooManyColumns()
127   {
128     /*
129      * with two too many columns:
130      */
131     String data = "ScoreMatrix MyTest\nX\tY\tZ\n1 2 3\n4 5 6 7\n8 9 10\n";
132     try
133     {
134       new ScoreMatrixFile(new FileParse(data, DataSourceType.PASTE))
135               .parseMatrix();
136       fail("expected exception");
137     } catch (IOException e)
138     {
139       assertEquals(e.getMessage(),
140               "Expected 3 scores at line 4: '4 5 6 7' but found 4");
141     }
142
143     /*
144      * with guide character and one too many columns:
145      */
146     data = "ScoreMatrix MyTest\nX Y\nX 1 2\nY 3 4 5\n";
147     try
148     {
149       new ScoreMatrixFile(new FileParse(data, DataSourceType.PASTE))
150               .parseMatrix();
151       fail("expected exception");
152     } catch (IOException e)
153     {
154       assertEquals(e.getMessage(),
155               "Expected 2 scores at line 4: 'Y 3 4 5' but found 3");
156     }
157
158     /*
159      * with no guide character and one too many columns
160      */
161     data = "ScoreMatrix MyTest\nX Y\n1 2\n3 4 5\n";
162     try
163     {
164       new ScoreMatrixFile(new FileParse(data, DataSourceType.PASTE))
165               .parseMatrix();
166       fail("expected exception");
167     } catch (IOException e)
168     {
169       assertEquals(e.getMessage(),
170               "Expected 2 scores at line 4: '3 4 5' but found 3");
171     }
172   }
173
174   @Test(groups = "Functional")
175   public void testParseMatrix_ncbiTooManyRows()
176   {
177     String data = "ScoreMatrix MyTest\n\tX\tY\tZ\n1 2 3\n4 5 6\n7 8 9\n10 11 12\n";
178     try
179     {
180       new ScoreMatrixFile(new FileParse(data, DataSourceType.PASTE))
181               .parseMatrix();
182       fail("expected exception");
183     } catch (IOException e)
184     {
185       assertEquals(e.getMessage(),
186               "Unexpected extra input line in score model file: '10 11 12'");
187     }
188   }
189
190   @Test(groups = "Functional")
191   public void testParseMatrix_ncbiBadDelimiter()
192   {
193     String data = "ScoreMatrix MyTest\n X Y Z\n1|2|3\n4|5|6\n";
194     try
195     {
196       new ScoreMatrixFile(new FileParse(data, DataSourceType.PASTE))
197               .parseMatrix();
198       fail("expected exception");
199     } catch (IOException e)
200     {
201       assertEquals(e.getMessage(),
202               "Invalid score value '1|2|3' at line 3 column 0");
203     }
204   }
205
206   @Test(groups = "Functional")
207   public void testParseMatrix_ncbiBadFloat()
208   {
209     String data = "ScoreMatrix MyTest\n\tX\tY\tZ\n1 2 3\n4 five 6\n7 8 9\n";
210     try
211     {
212       new ScoreMatrixFile(new FileParse(data, DataSourceType.PASTE))
213               .parseMatrix();
214       fail("expected exception");
215     } catch (IOException e)
216     {
217       assertEquals(e.getMessage(),
218               "Invalid score value 'five' at line 4 column 1");
219     }
220   }
221
222   @Test(groups = "Functional")
223   public void testParseMatrix_ncbiBadGuideCharacter()
224   {
225     String data = "ScoreMatrix MyTest\n\tX Y\nX 1 2\ny 3 4\n";
226     try
227     {
228       new ScoreMatrixFile(new FileParse(data, DataSourceType.PASTE))
229               .parseMatrix();
230       fail("expected exception");
231     } catch (IOException e)
232     {
233       assertEquals(e.getMessage(),
234               "Error parsing score matrix at line 4, expected 'Y' but found 'y'");
235     }
236
237     data = "ScoreMatrix MyTest\n\tX Y\nXX 1 2\nY 3 4\n";
238     try
239     {
240       new ScoreMatrixFile(new FileParse(data, DataSourceType.PASTE))
241               .parseMatrix();
242       fail("expected exception");
243     } catch (IOException e)
244     {
245       assertEquals(e.getMessage(),
246               "Error parsing score matrix at line 3, expected 'X' but found 'XX'");
247     }
248   }
249
250   @Test(groups = "Functional")
251   public void testParseMatrix_ncbiNameMissing()
252   {
253     /*
254      * Name missing on ScoreMatrix header line
255      */
256     String data = "ScoreMatrix\nX Y\n1 2\n3 4\n";
257     try
258     {
259       new ScoreMatrixFile(new FileParse(data, DataSourceType.PASTE))
260               .parseMatrix();
261       fail("expected exception");
262     } catch (IOException e)
263     {
264       assertEquals(e.getMessage(),
265               "Format error: expected 'ScoreMatrix <name>', found 'ScoreMatrix' at line 1");
266     }
267   }
268
269   /**
270    * Test a successful parse of a (small) score matrix file
271    * 
272    * @throws IOException
273    * @throws MalformedURLException
274    */
275   @Test(groups = "Functional")
276   public void testParseMatrix_ncbiFormat()
277           throws MalformedURLException, IOException
278   {
279     // input including comment and blank lines
280     String data = "ScoreMatrix MyTest\n#comment\n\n" + "\tA\tB\tC\n"
281             + "A\t1.0\t2.0\t3.0\n" + "B\t4.0\t5.0\t6.0\n"
282             + "C\t7.0\t8.0\t9.0\n";
283     FileParse fp = new FileParse(data, DataSourceType.PASTE);
284     ScoreMatrixFile parser = new ScoreMatrixFile(fp);
285     ScoreMatrix sm = parser.parseMatrix();
286
287     assertNotNull(sm);
288     assertEquals(sm.getName(), "MyTest");
289     assertEquals(parser.getMatrixName(), "MyTest");
290     assertEquals(sm.getPairwiseScore('A', 'A'), 1.0f);
291     assertEquals(sm.getPairwiseScore('B', 'c'), 6.0f);
292     assertEquals(sm.getSize(), 3);
293   }
294
295   /**
296    * Test a successful parse of a (small) score matrix file
297    * 
298    * @throws IOException
299    * @throws MalformedURLException
300    */
301   @Test(groups = "Functional")
302   public void testParseMatrix_aaIndexBlosum80()
303           throws MalformedURLException, IOException
304   {
305     FileParse fp = new FileParse("resources/scoreModel/blosum80.scm",
306             DataSourceType.FILE);
307     ScoreMatrixFile parser = new ScoreMatrixFile(fp);
308     ScoreMatrix sm = parser.parseMatrix();
309
310     assertNotNull(sm);
311     assertEquals(sm.getName(), "HENS920103");
312     assertEquals(sm.getDescription(),
313             "BLOSUM80 substitution matrix (Henikoff-Henikoff, 1992)");
314     assertFalse(sm.isDNA());
315     assertTrue(sm.isProtein());
316     assertEquals(20, sm.getSize());
317
318     assertEquals(sm.getPairwiseScore('A', 'A'), 7f);
319     assertEquals(sm.getPairwiseScore('A', 'R'), -3f);
320     assertEquals(sm.getPairwiseScore('r', 'a'), -3f); // A/a equivalent
321   }
322
323   /**
324    * Test a successful parse of a (small) score matrix file
325    * 
326    * @throws IOException
327    * @throws MalformedURLException
328    */
329   @Test(groups = "Functional")
330   public void testParseMatrix_aaindexFormat()
331           throws MalformedURLException, IOException
332   {
333     /*
334      * aaindex format has scores for diagonal and below only
335      */
336     String data = "H MyTest\n" + "D My description\n" + "R PMID:1438297\n"
337             + "A Authors, names\n" + "T Journal title\n"
338             + "J Journal reference\n" + "* matrix in 1/3 Bit Units\n"
339             + "M rows = ABC, cols = ABC\n" + "A\t1.0\n" + "B\t4.0\t5.0\n"
340             + "C\t7.0\t8.0\t9.0\n";
341     FileParse fp = new FileParse(data, DataSourceType.PASTE);
342     ScoreMatrixFile parser = new ScoreMatrixFile(fp);
343     ScoreMatrix sm = parser.parseMatrix();
344
345     assertNotNull(sm);
346     assertEquals(sm.getSize(), 3);
347     assertEquals(sm.getName(), "MyTest");
348     assertEquals(sm.getDescription(), "My description");
349     assertEquals(sm.getPairwiseScore('A', 'A'), 1.0f);
350     assertEquals(sm.getPairwiseScore('A', 'B'), 4.0f);
351     assertEquals(sm.getPairwiseScore('A', 'C'), 7.0f);
352     assertEquals(sm.getPairwiseScore('B', 'A'), 4.0f);
353     assertEquals(sm.getPairwiseScore('B', 'B'), 5.0f);
354     assertEquals(sm.getPairwiseScore('B', 'C'), 8.0f);
355     assertEquals(sm.getPairwiseScore('C', 'C'), 9.0f);
356     assertEquals(sm.getPairwiseScore('C', 'B'), 8.0f);
357     assertEquals(sm.getPairwiseScore('C', 'A'), 7.0f);
358   }
359
360   @Test(groups = "Functional")
361   public void testParseMatrix_aaindex_mMissing()
362           throws MalformedURLException, IOException
363   {
364     /*
365      * aaindex format but M cols=, rows= is missing
366      */
367     String data = "H MyTest\n" + "A\t1.0\n" + "B\t4.0\t5.0\n"
368             + "C\t7.0\t8.0\t9.0\n";
369     FileParse fp = new FileParse(data, DataSourceType.PASTE);
370     ScoreMatrixFile parser = new ScoreMatrixFile(fp);
371     try
372     {
373       parser.parseMatrix();
374       fail("Expected exception");
375     } catch (FileFormatException e)
376     {
377       assertEquals(e.getMessage(), "No alphabet specified in matrix file");
378     }
379   }
380
381   @Test(groups = "Functional")
382   public void testParseMatrix_aaindex_rowColMismatch()
383           throws MalformedURLException, IOException
384   {
385     String data = "H MyTest\n" + "M rows=ABC, cols=ABD\n" + "A\t1.0\n"
386             + "B\t4.0\t5.0\n" + "C\t7.0\t8.0\t9.0\n";
387     FileParse fp = new FileParse(data, DataSourceType.PASTE);
388     ScoreMatrixFile parser = new ScoreMatrixFile(fp);
389     try
390     {
391       parser.parseMatrix();
392       fail("Expected exception");
393     } catch (FileFormatException e)
394     {
395       assertEquals(e.getMessage(),
396               "Unexpected aaIndex score matrix data at line 2: M rows=ABC, cols=ABD rows != cols");
397     }
398   }
399
400   @Test(groups = "Functional")
401   public void testParseMatrix_ncbiHeaderRepeated()
402   {
403     String data = "ScoreMatrix BLOSUM\nScoreMatrix PAM250\nX Y\n1 2\n3 4\n";
404     try
405     {
406       new ScoreMatrixFile(new FileParse(data, DataSourceType.PASTE))
407               .parseMatrix();
408       fail("expected exception");
409     } catch (IOException e)
410     {
411       assertEquals(e.getMessage(),
412               "Error: 'ScoreMatrix' repeated in file at line 2");
413     }
414   }
415
416   @Test(groups = "Functional")
417   public void testParseMatrix_aaindex_tooManyRows()
418           throws MalformedURLException, IOException
419   {
420     String data = "H MyTest\n" + "M rows=ABC, cols=ABC\n" + "A\t1.0\n"
421             + "B\t4.0\t5.0\n" + "C\t7.0\t8.0\t9.0\n" + "C\t7.0\t8.0\t9.0\n";
422     FileParse fp = new FileParse(data, DataSourceType.PASTE);
423     ScoreMatrixFile parser = new ScoreMatrixFile(fp);
424     try
425     {
426       parser.parseMatrix();
427       fail("Expected exception");
428     } catch (FileFormatException e)
429     {
430       assertEquals(e.getMessage(), "Too many data rows in matrix file");
431     }
432   }
433
434   @Test(groups = "Functional")
435   public void testParseMatrix_aaindex_extraDataLines()
436           throws MalformedURLException, IOException
437   {
438     String data = "H MyTest\n" + "M rows=ABC, cols=ABC\n" + "A\t1.0\n"
439             + "B\t4.0\t5.0\n" + "C\t7.0\t8.0\t9.0\n" + "something extra\n";
440     FileParse fp = new FileParse(data, DataSourceType.PASTE);
441     ScoreMatrixFile parser = new ScoreMatrixFile(fp);
442     try
443     {
444       parser.parseMatrix();
445       fail("Expected exception");
446     } catch (FileFormatException e)
447     {
448       assertEquals(e.getMessage(), "Too many data rows in matrix file");
449     }
450   }
451
452   @Test(groups = "Functional")
453   public void testParseMatrix_aaindex_tooFewColumns()
454           throws MalformedURLException, IOException
455   {
456     String data = "H MyTest\n" + "M rows=ABC, cols=ABC\n" + "A\t1.0\n"
457             + "B\t4.0\t5.0\n" + "C\t7.0\t8.0\n";
458     FileParse fp = new FileParse(data, DataSourceType.PASTE);
459     ScoreMatrixFile parser = new ScoreMatrixFile(fp);
460     try
461     {
462       parser.parseMatrix();
463       fail("Expected exception");
464     } catch (FileFormatException e)
465     {
466       assertEquals(e.getMessage(),
467               "Expected 3 scores at line 5: 'C\t7.0\t8.0' but found 2");
468     }
469   }
470
471   /**
472    * Test a successful parse and register of a score matrix file
473    * 
474    * @throws IOException
475    * @throws MalformedURLException
476    */
477   @Test(groups = "Functional")
478   public void testParse_ncbiFormat()
479           throws MalformedURLException, IOException
480   {
481     assertNull(ScoreModels.getInstance().getScoreModel("MyNewTest", null));
482
483     String data = "ScoreMatrix MyNewTest\n" + "\tA\tB\tC\n"
484             + "A\t1.0\t2.0\t3.0\n" + "B\t4.0\t5.0\t6.0\n"
485             + "C\t7.0\t8.0\t9.0\n";
486     FileParse fp = new FileParse(data, DataSourceType.PASTE);
487     ScoreMatrixFile parser = new ScoreMatrixFile(fp);
488
489     parser.parse();
490
491     ScoreMatrix sm = (ScoreMatrix) ScoreModels.getInstance()
492             .getScoreModel("MyNewTest", null);
493     assertNotNull(sm);
494     assertEquals(sm.getName(), "MyNewTest");
495     assertEquals(parser.getMatrixName(), "MyNewTest");
496     assertEquals(sm.getPairwiseScore('A', 'A'), 1.0f);
497     assertEquals(sm.getPairwiseScore('B', 'c'), 6.0f);
498     assertEquals(sm.getSize(), 3);
499   }
500 }