JAL-2499 JAL-2403 push 'configure for view' inside ScoreModels, defer
[jalview.git] / test / jalview / analysis / scoremodels / ScoreMatrixTest.java
1 package jalview.analysis.scoremodels;
2
3 import static org.testng.Assert.assertEquals;
4 import static org.testng.Assert.assertFalse;
5 import static org.testng.Assert.assertNotEquals;
6 import static org.testng.Assert.assertNotNull;
7 import static org.testng.Assert.assertNotSame;
8 import static org.testng.Assert.assertNull;
9 import static org.testng.Assert.assertTrue;
10 import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
11
12 import jalview.api.analysis.SimilarityParamsI;
13 import jalview.io.DataSourceType;
14 import jalview.io.FileParse;
15 import jalview.io.ScoreMatrixFile;
16 import jalview.math.MatrixI;
17 import jalview.schemes.ResidueProperties;
18
19 import java.io.IOException;
20 import java.net.MalformedURLException;
21 import java.util.Arrays;
22
23 import org.testng.annotations.Test;
24
25 public class ScoreMatrixTest
26 {
27   @Test(groups = "Functional")
28   public void testConstructor()
29   {
30     // note score matrix does not have to be symmetric (though it should be!)
31     float[][] scores = new float[3][];
32     scores[0] = new float[] { 1f, 2f, 3f };
33     scores[1] = new float[] { -4f, 5f, 6f };
34     scores[2] = new float[] { 7f, 8f, 9f };
35     ScoreMatrix sm = new ScoreMatrix("Test", "ABC".toCharArray(), scores);
36     assertEquals(sm.getSize(), 3);
37     assertArrayEquals(scores, sm.getMatrix());
38     assertEquals(sm.getPairwiseScore('A', 'a'), 1f);
39     assertEquals(sm.getPairwiseScore('b', 'c'), 6f);
40     assertEquals(sm.getPairwiseScore('c', 'b'), 8f);
41     assertEquals(sm.getMatrixIndex('c'), 2);
42     assertEquals(sm.getMatrixIndex(' '), -1);
43
44     // substitution to or from unknown symbol gets minimum score
45     assertEquals(sm.getPairwiseScore('A', 'D'), -4f);
46     assertEquals(sm.getPairwiseScore('D', 'A'), -4f);
47     // unknown-to-self gets a score of 1
48     assertEquals(sm.getPairwiseScore('D', 'D'), 1f);
49   }
50
51   @Test(
52     groups = "Functional",
53     expectedExceptions = { IllegalArgumentException.class })
54   public void testConstructor_matrixTooSmall()
55   {
56     float[][] scores = new float[2][];
57     scores[0] = new float[] { 1f, 2f };
58     scores[1] = new float[] { 3f, 4f };
59     new ScoreMatrix("Test", "ABC".toCharArray(), scores);
60   }
61
62   @Test(
63     groups = "Functional",
64     expectedExceptions = { IllegalArgumentException.class })
65   public void testConstructor_matrixTooBig()
66   {
67     float[][] scores = new float[2][];
68     scores[0] = new float[] { 1f, 2f };
69     scores[1] = new float[] { 3f, 4f };
70     new ScoreMatrix("Test", "A".toCharArray(), scores);
71   }
72
73   @Test(
74     groups = "Functional",
75     expectedExceptions = { IllegalArgumentException.class })
76   public void testConstructor_matrixNotSquare()
77   {
78     float[][] scores = new float[2][];
79     scores[0] = new float[] { 1f, 2f };
80     scores[1] = new float[] { 3f };
81     new ScoreMatrix("Test", "AB".toCharArray(), scores);
82   }
83
84   @Test(groups = "Functional")
85   public void testBuildSymbolIndex()
86   {
87     float[][] scores = new float[2][];
88     scores[0] = new float[] { 1f, 2f };
89     scores[1] = new float[] { 3f, 4f };
90     ScoreMatrix sm = new ScoreMatrix("Test", new char[] { 'A', '.' },
91             scores);
92     short[] index = sm.buildSymbolIndex("AX-yxYp".toCharArray());
93
94     assertEquals(index.length, 128); // ASCII character set size
95
96     assertEquals(index['A'], 0);
97     assertEquals(index['a'], 0); // lower-case mapping added
98     assertEquals(index['X'], 1);
99     assertEquals(index['-'], 2);
100     assertEquals(index['y'], 3); // lower-case override
101     assertEquals(index['x'], 4); // lower-case override
102     assertEquals(index['Y'], 5);
103     assertEquals(index['p'], 6);
104     assertEquals(index['P'], -1); // lower-case doesn't map upper-case
105
106     /*
107      * check all unmapped symbols have index for unmapped
108      */
109     for (int c = 0; c < index.length; c++)
110     {
111       if (!"AaXx-. Yyp".contains(String.valueOf((char) c)))
112       {
113         assertEquals(index[c], -1);
114       }
115     }
116   }
117
118   /**
119    * check that characters not in the basic ASCII set are simply ignored
120    */
121   @Test(groups = "Functional")
122   public void testBuildSymbolIndex_nonAscii()
123   {
124     float[][] scores = new float[2][];
125     scores[0] = new float[] { 1f, 2f };
126     scores[1] = new float[] { 3f, 4f };
127     ScoreMatrix sm = new ScoreMatrix("Test", new char[] { 'A', '.' },
128             scores);
129     char[] weird = new char[] { 128, 245, 'P' };
130     short[] index = sm.buildSymbolIndex(weird);
131     assertEquals(index.length, 128);
132     assertEquals(index['P'], 2);
133     assertEquals(index['p'], 2);
134     for (int c = 0; c < index.length; c++)
135     {
136       if (c != 'P' && c != 'p')
137       {
138         assertEquals(index[c], -1);
139       }
140     }
141   }
142
143   @Test(groups = "Functional")
144   public void testGetMatrix()
145   {
146     ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
147     float[][] m = sm.getMatrix();
148     assertEquals(m.length, sm.getSize());
149     assertEquals(m[2][4], -3f);
150     // verify a defensive copy is returned
151     float[][] m2 = sm.getMatrix();
152     assertNotSame(m, m2);
153     assertTrue(Arrays.deepEquals(m, m2));
154   }
155
156   @Test(groups = "Functional")
157   public void testGetMatrixIndex()
158   {
159     ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
160     assertEquals(sm.getMatrixIndex('A'), 0);
161     assertEquals(sm.getMatrixIndex('R'), 1);
162     assertEquals(sm.getMatrixIndex('r'), 1);
163     assertEquals(sm.getMatrixIndex('N'), 2);
164     assertEquals(sm.getMatrixIndex('D'), 3);
165     assertEquals(sm.getMatrixIndex('X'), 22);
166     assertEquals(sm.getMatrixIndex('x'), 22);
167     assertEquals(sm.getMatrixIndex('-'), -1);
168     assertEquals(sm.getMatrixIndex('*'), 23);
169     assertEquals(sm.getMatrixIndex('.'), -1);
170     assertEquals(sm.getMatrixIndex(' '), -1);
171     assertEquals(sm.getMatrixIndex('?'), -1);
172     assertEquals(sm.getMatrixIndex((char) 128), -1);
173   }
174
175   @Test(groups = "Functional")
176   public void testGetSize()
177   {
178     ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
179     assertEquals(sm.getMatrix().length, sm.getSize());
180   }
181
182   @Test(groups = "Functional")
183   public void testComputePairwiseScores()
184   {
185     /*
186      * NB score matrix expects '-' for gap
187      */
188     String[] seqs = new String[] { "FKL", "R-D", "QIA", "GWC" };
189     ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
190
191     MatrixI pairwise = sm.findSimilarities(seqs, SimilarityParams.Jalview);
192
193     /*
194      * should be NxN where N = number of sequences
195      */
196     assertEquals(pairwise.height(), 4);
197     assertEquals(pairwise.width(), 4);
198
199     /*
200      * should be symmetrical (because BLOSUM62 is)
201      */
202     for (int i = 0; i < pairwise.height(); i++)
203     {
204       for (int j = i + 1; j < pairwise.width(); j++)
205       {
206         assertEquals(pairwise.getValue(i, j), pairwise.getValue(j, i),
207                 String.format("Not symmetric at [%d, %d]", i, j));
208       }
209     }
210     /*
211      * verify expected BLOSUM dot product scores
212      */
213     // F.F + K.K + L.L = 6 + 5 + 4 = 15
214     assertEquals(pairwise.getValue(0, 0), 15d);
215     // R.R + -.- + D.D = 5 + 1 + 6 = 12
216     assertEquals(pairwise.getValue(1, 1), 12d);
217     // Q.Q + I.I + A.A = 5 + 4 + 4 = 13
218     assertEquals(pairwise.getValue(2, 2), 13d);
219     // G.G + W.W + C.C = 6 + 11 + 9 = 26
220     assertEquals(pairwise.getValue(3, 3), 26d);
221     // F.R + K.- + L.D = -3 + -4 + -4 = -11
222     assertEquals(pairwise.getValue(0, 1), -11d);
223     // F.Q + K.I + L.A = -3 + -3 + -1 = -7
224     assertEquals(pairwise.getValue(0, 2), -7d);
225     // F.G + K.W + L.C = -3 + -3 + -1 = -7
226     assertEquals(pairwise.getValue(0, 3), -7d);
227     // R.Q + -.I + D.A = 1 + -4 + -2 = -5
228     assertEquals(pairwise.getValue(1, 2), -5d);
229     // R.G + -.W + D.C = -2 + -4 + -3 = -9
230     assertEquals(pairwise.getValue(1, 3), -9d);
231     // Q.G + I.W + A.C = -2 + -3 + 0 = -5
232     assertEquals(pairwise.getValue(2, 3), -5d);
233   }
234
235   /**
236    * Test that the result of outputMatrix can be reparsed to give an identical
237    * ScoreMatrix
238    * 
239    * @throws IOException
240    * @throws MalformedURLException
241    */
242   @Test(groups = "Functional")
243   public void testOutputMatrix_roundTrip() throws MalformedURLException,
244           IOException
245   {
246     ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
247     String output = sm.outputMatrix(false);
248     FileParse fp = new FileParse(output, DataSourceType.PASTE);
249     ScoreMatrixFile parser = new ScoreMatrixFile(fp);
250     ScoreMatrix sm2 = parser.parseMatrix();
251     assertNotNull(sm2);
252     assertTrue(sm2.equals(sm));
253   }
254
255   @Test(groups = "Functional")
256   public void testEqualsAndHashCode()
257   {
258     ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
259     ScoreMatrix sm2 = new ScoreMatrix(sm.getName(), sm.getSymbols()
260             .toCharArray(), sm.getMatrix());
261     assertTrue(sm.equals(sm2));
262     assertEquals(sm.hashCode(), sm2.hashCode());
263
264     sm2 = ScoreModels.getInstance().getPam250();
265     assertFalse(sm.equals(sm2));
266     assertNotEquals(sm.hashCode(), sm2.hashCode());
267
268     assertFalse(sm.equals("hello"));
269   }
270
271   /**
272    * Tests for scoring options where the longer length of two sequences is used
273    */
274   @Test(groups = "Functional")
275   public void testcomputeSimilarity_matchLongestSequence()
276   {
277     /*
278      * ScoreMatrix expects '-' for gaps
279      */
280     String s1 = "FR-K-S";
281     String s2 = "FS--L";
282     ScoreMatrix blosum = ScoreModels.getInstance().getBlosum62();
283   
284     /*
285      * score gap-gap and gap-char
286      * shorter sequence treated as if with trailing gaps
287      * score = F^F + R^S + -^- + K^- + -^L + S^-
288      * = 6 + -1 + 1 + -4 + -4 + -4 = -6
289      */
290     SimilarityParamsI params = new SimilarityParams(true, true, true, false);
291     assertEquals(blosum.computeSimilarity(s1, s2, params), -6d);
292     // matchGap (arg2) is ignored:
293     params = new SimilarityParams(true, false, true, false);
294     assertEquals(blosum.computeSimilarity(s1, s2, params), -6d);
295   
296     /*
297      * score gap-char but not gap-gap
298      * score = F^F + R^S + 0 + K^- + -^L + S^-
299      * = 6 + -1 + 0 + -4 + -4 + -4 = -7
300      */
301     params = new SimilarityParams(false, true, true, false);
302     assertEquals(blosum.computeSimilarity(s1, s2, params), -7d);
303     // matchGap (arg2) is ignored:
304     params = new SimilarityParams(false, false, true, false);
305     assertEquals(blosum.computeSimilarity(s1, s2, params), -7d);
306   
307     /*
308      * score gap-gap but not gap-char
309      * score = F^F + R^S + -^- + 0 + 0 + 0
310      * = 6 + -1 + 1 = 6
311      */
312     params = new SimilarityParams(true, false, false, false);
313     assertEquals(blosum.computeSimilarity(s1, s2, params), 6d);
314     // matchGap (arg2) is ignored:
315     params = new SimilarityParams(true, true, false, false);
316     assertEquals(blosum.computeSimilarity(s1, s2, params), 6d);
317   
318     /*
319      * score neither gap-gap nor gap-char
320      * score = F^F + R^S + 0 + 0 + 0 + 0
321      * = 6 + -1  = 5
322      */
323     params = new SimilarityParams(false, false, false, false);
324     assertEquals(blosum.computeSimilarity(s1, s2, params), 5d);
325     // matchGap (arg2) is ignored:
326     params = new SimilarityParams(false, true, false, false);
327     assertEquals(blosum.computeSimilarity(s1, s2, params), 5d);
328   }
329
330   /**
331    * Tests for scoring options where only the shorter length of two sequences is
332    * used
333    */
334   @Test(groups = "Functional")
335   public void testcomputeSimilarity_matchShortestSequence()
336   {
337     /*
338      * ScoreMatrix expects '-' for gaps
339      */
340     String s1 = "FR-K-S";
341     String s2 = "FS--L";
342     ScoreMatrix blosum = ScoreModels.getInstance().getBlosum62();
343
344     /*
345      * score gap-gap and gap-char
346      * match shorter sequence only
347      * score = F^F + R^S + -^- + K^- + -^L
348      * = 6 + -1 + 1 + -4 + -4 = -2
349      */
350     SimilarityParamsI params = new SimilarityParams(true, true, true, true);
351     assertEquals(blosum.computeSimilarity(s1, s2, params), -2d);
352     // matchGap (arg2) is ignored:
353     params = new SimilarityParams(true, false, true, true);
354     assertEquals(blosum.computeSimilarity(s1, s2, params), -2d);
355   
356     /*
357      * score gap-char but not gap-gap
358      * score = F^F + R^S + 0 + K^- + -^L
359      * = 6 + -1 + 0 + -4 + -4 = -3
360      */
361     params = new SimilarityParams(false, true, true, true);
362     assertEquals(blosum.computeSimilarity(s1, s2, params), -3d);
363     // matchGap (arg2) is ignored:
364     params = new SimilarityParams(false, false, true, true);
365     assertEquals(blosum.computeSimilarity(s1, s2, params), -3d);
366   
367     /*
368      * score gap-gap but not gap-char
369      * score = F^F + R^S + -^- + 0 + 0
370      * = 6 + -1 + 1 = 6
371      */
372     params = new SimilarityParams(true, false, false, true);
373     assertEquals(blosum.computeSimilarity(s1, s2, params), 6d);
374     // matchGap (arg2) is ignored:
375     params = new SimilarityParams(true, true, false, true);
376     assertEquals(blosum.computeSimilarity(s1, s2, params), 6d);
377   
378     /*
379      * score neither gap-gap nor gap-char
380      * score = F^F + R^S + 0 + 0 + 0
381      * = 6 + -1  = 5
382      */
383     params = new SimilarityParams(false, false, false, true);
384     assertEquals(blosum.computeSimilarity(s1, s2, params), 5d);
385     // matchGap (arg2) is ignored:
386     params = new SimilarityParams(false, true, false, true);
387     assertEquals(blosum.computeSimilarity(s1, s2, params), 5d);
388   }
389
390   @Test(groups = "Functional")
391   public void testSymmetric()
392   {
393     verifySymmetric(ScoreModels.getInstance().getBlosum62());
394     verifySymmetric(ScoreModels.getInstance().getPam250());
395     verifySymmetric(ScoreModels.getInstance().getDefaultModel(false)); // dna
396   }
397
398   private void verifySymmetric(ScoreMatrix sm)
399   {
400     float[][] m = sm.getMatrix();
401     int rows = m.length;
402     for (int row = 0; row < rows; row++)
403     {
404       assertEquals(m[row].length, rows);
405       for (int col = 0; col < rows; col++)
406       {
407         assertEquals(m[row][col], m[col][row], String.format("%s [%s, %s]",
408                 sm.getName(), ResidueProperties.aa[row],
409                 ResidueProperties.aa[col]));
410       }
411     }
412   }
413
414   /**
415    * A test that just asserts the expected values in the Blosum62 score matrix
416    */
417   @Test(groups = "Functional")
418   public void testBlosum62_values()
419   {
420     ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
421
422     assertTrue(sm.isProtein());
423     assertFalse(sm.isDNA());
424     assertNull(sm.getDescription());
425
426     /*
427      * verify expected scores against ARNDCQEGHILKMFPSTWYVBZX
428      * scraped from https://www.ncbi.nlm.nih.gov/Class/FieldGuide/BLOSUM62.txt
429      */
430     verifyValues(sm, 'A', new float[] { 4, -1, -2, -2, 0, -1, -1, 0, -2,
431         -1,
432         -1, -1, -1, -2, -1, 1, 0, -3, -2, 0, -2, -1, 0 });
433     verifyValues(sm, 'R', new float[] { -1, 5, 0, -2, -3, 1, 0, -2, 0, -3,
434         -2, 2, -1, -3, -2, -1, -1, -3, -2, -3, -1, 0, -1 });
435     verifyValues(sm, 'N', new float[] { -2, 0, 6, 1, -3, 0, 0, 0, 1, -3,
436         -3,
437         0, -2, -3, -2, 1, 0, -4, -2, -3, 3, 0, -1 });
438     verifyValues(sm, 'D', new float[] { -2, -2, 1, 6, -3, 0, 2, -1, -1, -3,
439         -4, -1, -3, -3, -1, 0, -1, -4, -3, -3, 4, 1, -1 });
440     verifyValues(sm, 'C', new float[] { 0, -3, -3, -3, 9, -3, -4, -3, -3,
441         -1,
442         -1, -3, -1, -2, -3, -1, -1, -2, -2, -1, -3, -3, -2 });
443     verifyValues(sm, 'Q', new float[] { -1, 1, 0, 0, -3, 5, 2, -2, 0, -3,
444         -2,
445         1, 0, -3, -1, 0, -1, -2, -1, -2, 0, 3, -1 });
446     verifyValues(sm, 'E', new float[] { -1, 0, 0, 2, -4, 2, 5, -2, 0, -3,
447         -3,
448         1, -2, -3, -1, 0, -1, -3, -2, -2, 1, 4, -1 });
449     verifyValues(sm, 'G', new float[] { 0, -2, 0, -1, -3, -2, -2, 6, -2,
450         -4,
451         -4, -2, -3, -3, -2, 0, -2, -2, -3, -3, -1, -2, -1 });
452     verifyValues(sm, 'H', new float[] { -2, 0, 1, -1, -3, 0, 0, -2, 8, -3,
453         -3, -1, -2, -1, -2, -1, -2, -2, 2, -3, 0, 0, -1 });
454     verifyValues(sm, 'I', new float[] { -1, -3, -3, -3, -1, -3, -3, -4, -3,
455         4, 2, -3, 1, 0, -3, -2, -1, -3, -1, 3, -3, -3, -1 });
456     verifyValues(sm, 'L', new float[] { -1, -2, -3, -4, -1, -2, -3, -4, -3,
457         2, 4, -2, 2, 0, -3, -2, -1, -2, -1, 1, -4, -3, -1 });
458     verifyValues(sm, 'K', new float[] { -1, 2, 0, -1, -3, 1, 1, -2, -1, -3,
459         -2, 5, -1, -3, -1, 0, -1, -3, -2, -2, 0, 1, -1 });
460     verifyValues(sm, 'M', new float[] { -1, -1, -2, -3, -1, 0, -2, -3, -2,
461         1,
462         2, -1, 5, 0, -2, -1, -1, -1, -1, 1, -3, -1, -1 });
463     verifyValues(sm, 'F', new float[] { -2, -3, -3, -3, -2, -3, -3, -3, -1,
464         0, 0, -3, 0, 6, -4, -2, -2, 1, 3, -1, -3, -3, -1 });
465     verifyValues(sm, 'P', new float[] { -1, -2, -2, -1, -3, -1, -1, -2, -2,
466         -3, -3, -1, -2, -4, 7, -1, -1, -4, -3, -2, -2, -1, -2 });
467     verifyValues(sm, 'S', new float[] { 1, -1, 1, 0, -1, 0, 0, 0, -1, -2,
468         -2,
469         0, -1, -2, -1, 4, 1, -3, -2, -2, 0, 0, 0 });
470     verifyValues(sm, 'T', new float[] { 0, -1, 0, -1, -1, -1, -1, -2, -2,
471         -1,
472         -1, -1, -1, -2, -1, 1, 5, -2, -2, 0, -1, -1, 0 });
473     verifyValues(sm, 'W', new float[] { -3, -3, -4, -4, -2, -2, -3, -2, -2,
474         -3, -2, -3, -1, 1, -4, -3, -2, 11, 2, -3, -4, -3, -2 });
475     verifyValues(sm, 'Y', new float[] { -2, -2, -2, -3, -2, -1, -2, -3, 2,
476         -1, -1, -2, -1, 3, -3, -2, -2, 2, 7, -1, -3, -2, -1 });
477     verifyValues(sm, 'V', new float[] { 0, -3, -3, -3, -1, -2, -2, -3, -3,
478         3,
479         1, -2, 1, -1, -2, -2, 0, -3, -1, 4, -3, -2, -1 });
480     verifyValues(sm, 'B', new float[] { -2, -1, 3, 4, -3, 0, 1, -1, 0, -3,
481         -4, 0, -3, -3, -2, 0, -1, -4, -3, -3, 4, 1, -1 });
482     verifyValues(sm, 'Z', new float[] { -1, 0, 0, 1, -3, 3, 4, -2, 0, -3,
483         -3,
484         1, -1, -3, -1, 0, -1, -3, -2, -2, 1, 4, -1 });
485     verifyValues(sm, 'X', new float[] { 0, -1, -1, -1, -2, -1, -1, -1, -1,
486         -1, -1, -1, -1, -1, -2, 0, 0, -2, -1, -1, -1, -1, -1 });
487   }
488
489   /**
490    * Helper method to check pairwise scores for one residue
491    * 
492    * @param sm
493    * @param res
494    * @param expected
495    *          score values against 'res', in ResidueProperties.aaIndex order
496    */
497   private void verifyValues(ScoreMatrix sm, char res, float[] expected)
498   {
499     for (int j = 0; j < expected.length; j++)
500     {
501       char c2 = ResidueProperties.aa[j].charAt(0);
502       assertEquals(sm.getPairwiseScore(res, c2), expected[j],
503               String.format("%s->%s", res, c2));
504     }
505   }
506
507   @Test(groups = "Functional")
508   public void testConstructor_gapDash()
509   {
510     float[][] scores = new float[2][];
511     scores[0] = new float[] { 1f, 2f };
512     scores[1] = new float[] { 4f, 5f };
513     ScoreMatrix sm = new ScoreMatrix("Test", new char[] { 'A', '-' },
514             scores);
515     assertEquals(sm.getSize(), 2);
516     assertArrayEquals(scores, sm.getMatrix());
517     assertEquals(sm.getPairwiseScore('A', 'a'), 1f);
518     assertEquals(sm.getPairwiseScore('A', 'A'), 1f);
519     assertEquals(sm.getPairwiseScore('a', '-'), 2f);
520     assertEquals(sm.getPairwiseScore('-', 'A'), 4f);
521     assertEquals(sm.getMatrixIndex('a'), 0);
522     assertEquals(sm.getMatrixIndex('A'), 0);
523     assertEquals(sm.getMatrixIndex('-'), 1);
524     assertEquals(sm.getMatrixIndex(' '), -1);
525     assertEquals(sm.getMatrixIndex('.'), -1);
526   }
527
528   @Test(groups = "Functional")
529   public void testGetPairwiseScore()
530   {
531     float[][] scores = new float[2][];
532     scores[0] = new float[] { 1f, 2f };
533     scores[1] = new float[] { -4f, 5f };
534     ScoreMatrix sm = new ScoreMatrix("Test", new char[] { 'A', 'B' },
535             scores);
536     assertEquals(sm.getPairwiseScore('A', 'A'), 1f);
537     assertEquals(sm.getPairwiseScore('A', 'a'), 1f);
538     assertEquals(sm.getPairwiseScore('A', 'B'), 2f);
539     assertEquals(sm.getPairwiseScore('b', 'a'), -4f);
540     assertEquals(sm.getPairwiseScore('B', 'b'), 5f);
541
542     /*
543      * unknown symbols currently score minimum score
544      * or 1 for identity with self
545      */
546     assertEquals(sm.getPairwiseScore('A', '-'), -4f);
547     assertEquals(sm.getPairwiseScore('-', 'A'), -4f);
548     assertEquals(sm.getPairwiseScore('-', '-'), 1f);
549     assertEquals(sm.getPairwiseScore('Q', 'W'), -4f);
550     assertEquals(sm.getPairwiseScore('Q', 'Q'), 1f);
551
552     /*
553      * symbols not in basic ASCII set score zero
554      */
555     char c = (char) 200;
556     assertEquals(sm.getPairwiseScore('Q', c), 0f);
557     assertEquals(sm.getPairwiseScore(c, 'Q'), 0f);
558   }
559
560   @Test(groups = "Functional")
561   public void testGetMinimumScore()
562   {
563     ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
564     assertEquals(sm.getMinimumScore(), -4f);
565   }
566
567   @Test(groups = "Functional")
568   public void testGetMaximumScore()
569   {
570     ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
571     assertEquals(sm.getMaximumScore(), 11f);
572   }
573
574   @Test(groups = "Functional")
575   public void testOutputMatrix_html()
576   {
577     float[][] scores = new float[2][];
578     scores[0] = new float[] { 1f, 2f };
579     scores[1] = new float[] { 4f, -5.3E-10f };
580     ScoreMatrix sm = new ScoreMatrix("Test", "AB".toCharArray(), scores);
581     String html = sm.outputMatrix(true);
582     String expected = "<table border=\"1\"><tr><th></th><th>&nbsp;A&nbsp;</th><th>&nbsp;B&nbsp;</th></tr>\n"
583             + "<tr><td>A</td><td>1.0</td><td>2.0</td></tr>\n"
584             + "<tr><td>B</td><td>4.0</td><td>-5.3E-10</td></tr>\n"
585             + "</table>";
586     assertEquals(html, expected);
587   }
588 }