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