JAL-3438 spotless for 2.11.2.0
[jalview.git] / test / jalview / schemes / FeatureColourTest.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.schemes;
22
23 import static org.testng.AssertJUnit.assertEquals;
24 import static org.testng.AssertJUnit.assertFalse;
25 import static org.testng.AssertJUnit.assertNull;
26 import static org.testng.AssertJUnit.assertTrue;
27 import static org.testng.AssertJUnit.fail;
28 import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
29
30 import jalview.api.FeatureColourI;
31 import jalview.datamodel.SequenceFeature;
32 import jalview.gui.JvOptionPane;
33 import jalview.util.ColorUtils;
34 import jalview.util.Format;
35
36 import java.awt.Color;
37
38 import org.testng.annotations.BeforeClass;
39 import org.testng.annotations.Test;
40
41 public class FeatureColourTest
42 {
43
44   @BeforeClass(alwaysRun = true)
45   public void setUpJvOptionPane()
46   {
47     JvOptionPane.setInteractiveMode(false);
48     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
49   }
50
51   @Test(groups = { "Functional" })
52   public void testConstructors()
53   {
54     FeatureColourI fc = new FeatureColour();
55     assertNull(fc.getColour());
56     assertTrue(fc.isSimpleColour());
57     assertFalse(fc.isColourByLabel());
58     assertFalse(fc.isGraduatedColour());
59     assertFalse(fc.isColourByAttribute());
60     assertEquals(Color.white, fc.getMinColour());
61     assertEquals(Color.black, fc.getMaxColour());
62
63     fc = new FeatureColour(Color.RED);
64     assertEquals(Color.red, fc.getColour());
65     assertTrue(fc.isSimpleColour());
66     assertFalse(fc.isColourByLabel());
67     assertFalse(fc.isGraduatedColour());
68     assertFalse(fc.isColourByAttribute());
69     assertEquals(ColorUtils.bleachColour(Color.RED, 0.9f),
70             fc.getMinColour());
71     assertEquals(Color.RED, fc.getMaxColour());
72
73   }
74
75   @Test(groups = { "Functional" })
76   public void testCopyConstructor()
77   {
78     /*
79      * plain colour
80      */
81     FeatureColour fc = new FeatureColour(Color.RED);
82     FeatureColour fc1 = new FeatureColour(fc);
83     assertTrue(fc1.getColour().equals(Color.RED));
84     assertFalse(fc1.isGraduatedColour());
85     assertFalse(fc1.isColourByLabel());
86     assertFalse(fc1.isColourByAttribute());
87     assertNull(fc1.getAttributeName());
88
89     /*
90      * min-max colour
91      */
92     fc = new FeatureColour(null, Color.gray, Color.black, Color.gray, 10f,
93             20f);
94     fc.setAboveThreshold(true);
95     fc.setThreshold(12f);
96     fc1 = new FeatureColour(fc);
97     assertTrue(fc1.isGraduatedColour());
98     assertFalse(fc1.isColourByLabel());
99     assertTrue(fc1.isAboveThreshold());
100     assertFalse(fc1.isColourByAttribute());
101     assertNull(fc1.getAttributeName());
102     assertEquals(12f, fc1.getThreshold());
103     assertEquals(Color.gray, fc1.getMinColour());
104     assertEquals(Color.black, fc1.getMaxColour());
105     assertEquals(Color.gray, fc1.getNoColour());
106     assertEquals(10f, fc1.getMin());
107     assertEquals(20f, fc1.getMax());
108
109     /*
110      * min-max-noValue colour
111      */
112     fc = new FeatureColour(Color.red, Color.gray, Color.black, Color.green,
113             10f, 20f);
114     fc.setAboveThreshold(true);
115     fc.setThreshold(12f);
116     fc1 = new FeatureColour(fc);
117     assertTrue(fc1.isGraduatedColour());
118     assertFalse(fc1.isColourByLabel());
119     assertFalse(fc1.isSimpleColour());
120     assertFalse(fc1.isColourByAttribute());
121     assertNull(fc1.getAttributeName());
122     assertTrue(fc1.isAboveThreshold());
123     assertEquals(12f, fc1.getThreshold());
124     assertEquals(Color.gray, fc1.getMinColour());
125     assertEquals(Color.black, fc1.getMaxColour());
126     assertEquals(Color.green, fc1.getNoColour());
127     assertEquals(Color.red, fc1.getColour());
128     assertEquals(10f, fc1.getMin());
129     assertEquals(20f, fc1.getMax());
130
131     /*
132      * colour by label
133      */
134     fc = new FeatureColour();
135     fc.setColourByLabel(true);
136     fc1 = new FeatureColour(fc);
137     assertTrue(fc1.isColourByLabel());
138     assertFalse(fc1.isGraduatedColour());
139     assertFalse(fc1.isColourByAttribute());
140     assertNull(fc1.getAttributeName());
141
142     /*
143      * colour by attribute (label)
144      */
145     fc = new FeatureColour();
146     fc.setColourByLabel(true);
147     fc.setAttributeName("AF");
148     fc1 = new FeatureColour(fc);
149     assertTrue(fc1.isColourByLabel());
150     assertFalse(fc1.isGraduatedColour());
151     assertTrue(fc1.isColourByAttribute());
152     assertArrayEquals(new String[] { "AF" }, fc1.getAttributeName());
153
154     /*
155      * colour by attribute (value)
156      */
157     fc = new FeatureColour(Color.yellow, Color.gray, Color.black,
158             Color.green, 10f, 20f);
159     fc.setAboveThreshold(true);
160     fc.setThreshold(12f);
161     fc.setAttributeName("AF");
162     fc1 = new FeatureColour(fc);
163     assertTrue(fc1.isGraduatedColour());
164     assertFalse(fc1.isColourByLabel());
165     assertTrue(fc1.isColourByAttribute());
166     assertFalse(fc1.isSimpleColour());
167     assertArrayEquals(new String[] { "AF" }, fc1.getAttributeName());
168     assertTrue(fc1.isAboveThreshold());
169     assertEquals(12f, fc1.getThreshold());
170     assertEquals(Color.gray, fc1.getMinColour());
171     assertEquals(Color.black, fc1.getMaxColour());
172     assertEquals(Color.green, fc1.getNoColour());
173     assertEquals(Color.yellow, fc1.getColour());
174     assertEquals(10f, fc1.getMin());
175     assertEquals(20f, fc1.getMax());
176
177     /*
178      * modify original attribute label and check that copy doesn't change
179      */
180     fc.setAttributeName("MAF", "AF");
181     assertArrayEquals(new String[] { "AF" }, fc1.getAttributeName());
182
183   }
184
185   @Test(groups = { "Functional" })
186   public void testGetColor_simpleColour()
187   {
188     FeatureColour fc = new FeatureColour(Color.RED);
189     assertEquals(Color.RED,
190             fc.getColor(new SequenceFeature("Cath", "", 1, 2, 0f, null)));
191   }
192
193   @Test(groups = { "Functional" })
194   public void testGetColor_colourByLabel()
195   {
196     FeatureColour fc = new FeatureColour();
197     fc.setColourByLabel(true);
198     SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 1f,
199             null);
200     Color expected = ColorUtils.createColourFromName("desc");
201     assertEquals(expected, fc.getColor(sf));
202   }
203
204   @Test(groups = { "Functional" })
205   public void testGetColor_Graduated()
206   {
207     /*
208      * graduated colour from 
209      * score 0 to 100
210      * gray(128, 128, 128) to red(255, 0, 0)
211      */
212     FeatureColour fc = new FeatureColour(null, Color.GRAY, Color.RED, null,
213             0f, 100f);
214     // feature score is 75 which is 3/4 of the way from GRAY to RED
215     SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 75f,
216             null);
217     // the colour gradient is computed in float values from 0-1 (where 1 == 255)
218     float red = 128 / 255f + 3 / 4f * (255 - 128) / 255f;
219     float green = 128 / 255f + 3 / 4f * (0 - 128) / 255f;
220     float blue = 128 / 255f + 3 / 4f * (0 - 128) / 255f;
221     Color expected = new Color(red, green, blue);
222     assertEquals(expected, fc.getColor(sf));
223   }
224
225   @Test(groups = { "Functional" })
226   public void testGetColor_aboveBelowThreshold()
227   {
228     // gradient from [50, 150] from WHITE(255, 255, 255) to BLACK(0, 0, 0)
229     FeatureColour fc = new FeatureColour(null, Color.WHITE, Color.BLACK,
230             Color.white, 50f, 150f);
231     SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 70f,
232             null);
233
234     /*
235      * feature with score of Float.NaN is always assigned minimum colour
236      */
237     SequenceFeature sf2 = new SequenceFeature("type", "desc", 0, 20,
238             Float.NaN, null);
239
240     fc.setThreshold(100f); // ignore for now
241     assertEquals(new Color(204, 204, 204), fc.getColor(sf));
242     assertEquals(Color.white, fc.getColor(sf2));
243
244     fc.setAboveThreshold(true); // feature lies below threshold
245     assertNull(fc.getColor(sf));
246     assertEquals(Color.white, fc.getColor(sf2));
247
248     fc.setBelowThreshold(true);
249     fc.setThreshold(70f);
250     assertNull(fc.getColor(sf)); // feature score == threshold - hidden
251     assertEquals(Color.white, fc.getColor(sf2));
252     fc.setThreshold(69f);
253     assertNull(fc.getColor(sf)); // feature score > threshold - hidden
254     assertEquals(Color.white, fc.getColor(sf2));
255   }
256
257   /**
258    * Test output of feature colours to Jalview features file format
259    */
260   @Test(groups = { "Functional" })
261   public void testToJalviewFormat()
262   {
263     /*
264      * plain colour - to RGB hex code
265      */
266     FeatureColour fc = new FeatureColour(Color.RED);
267     String redHex = Format.getHexString(Color.RED);
268     String hexColour = redHex;
269     assertEquals("domain\t" + hexColour, fc.toJalviewFormat("domain"));
270
271     /*
272      * colour by label (no threshold)
273      */
274     fc = new FeatureColour();
275     fc.setColourByLabel(true);
276     assertEquals("domain\tlabel", fc.toJalviewFormat("domain"));
277
278     /*
279      * colour by attribute text (no threshold)
280      */
281     fc = new FeatureColour();
282     fc.setColourByLabel(true);
283     fc.setAttributeName("CLIN_SIG");
284     assertEquals("domain\tattribute|CLIN_SIG",
285             fc.toJalviewFormat("domain"));
286
287     /*
288      * colour by label (autoscaled) (an odd state you can reach by selecting
289      * 'above threshold', then deselecting 'threshold is min/max' then 'colour
290      * by label')
291      */
292     fc.setAttributeName((String[]) null);
293     fc.setAutoScaled(true);
294     assertEquals("domain\tlabel", fc.toJalviewFormat("domain"));
295
296     /*
297      * colour by label (above threshold) 
298      */
299     fc.setAutoScaled(false);
300     fc.setThreshold(12.5f);
301     fc.setAboveThreshold(true);
302     // min/max values are output though not used by this scheme
303     assertEquals("domain\tlabel|||0.0|0.0|above|12.5",
304             fc.toJalviewFormat("domain"));
305
306     /*
307      * colour by label (below threshold)
308      */
309     fc.setBelowThreshold(true);
310     assertEquals("domain\tlabel|||0.0|0.0|below|12.5",
311             fc.toJalviewFormat("domain"));
312
313     /*
314      * colour by attributes text (below threshold)
315      */
316     fc.setBelowThreshold(true);
317     fc.setAttributeName("CSQ", "Consequence");
318     assertEquals("domain\tattribute|CSQ:Consequence|||0.0|0.0|below|12.5",
319             fc.toJalviewFormat("domain"));
320
321     /*
322      * graduated colour by score, no threshold
323      * - default constructor sets noValueColor = minColor
324      */
325     fc = new FeatureColour(null, Color.GREEN, Color.RED, Color.GREEN, 12f,
326             25f);
327     String greenHex = Format.getHexString(Color.GREEN);
328     String expected = String.format(
329             "domain\tscore|%s|%s|noValueMin|abso|12.0|25.0|none", greenHex,
330             redHex);
331     assertEquals(expected, fc.toJalviewFormat("domain"));
332
333     /*
334      * graduated colour by score, no threshold, no value gets min colour
335      */
336     fc = new FeatureColour(Color.RED, Color.GREEN, Color.RED, Color.GREEN,
337             12f, 25f);
338     expected = String.format(
339             "domain\tscore|%s|%s|noValueMin|abso|12.0|25.0|none", greenHex,
340             redHex);
341     assertEquals(expected, fc.toJalviewFormat("domain"));
342
343     /*
344      * graduated colour by score, no threshold, no value gets max colour
345      */
346     fc = new FeatureColour(Color.RED, Color.GREEN, Color.RED, Color.RED,
347             12f, 25f);
348     expected = String.format(
349             "domain\tscore|%s|%s|noValueMax|abso|12.0|25.0|none", greenHex,
350             redHex);
351     assertEquals(expected, fc.toJalviewFormat("domain"));
352
353     /*
354      * colour ranges over the actual score ranges (not min/max)
355      */
356     fc.setAutoScaled(true);
357     expected = String.format(
358             "domain\tscore|%s|%s|noValueMax|12.0|25.0|none", greenHex,
359             redHex);
360     assertEquals(expected, fc.toJalviewFormat("domain"));
361
362     /*
363      * graduated colour by score, below threshold
364      */
365     fc.setThreshold(12.5f);
366     fc.setBelowThreshold(true);
367     expected = String.format(
368             "domain\tscore|%s|%s|noValueMax|12.0|25.0|below|12.5", greenHex,
369             redHex);
370     assertEquals(expected, fc.toJalviewFormat("domain"));
371
372     /*
373      * graduated colour by score, above threshold
374      */
375     fc.setThreshold(12.5f);
376     fc.setAboveThreshold(true);
377     fc.setAutoScaled(false);
378     expected = String.format(
379             "domain\tscore|%s|%s|noValueMax|abso|12.0|25.0|above|12.5",
380             greenHex, redHex);
381     assertEquals(expected, fc.toJalviewFormat("domain"));
382
383     /*
384      * graduated colour by attribute, above threshold
385      */
386     fc.setAttributeName("CSQ", "AF");
387     fc.setAboveThreshold(true);
388     fc.setAutoScaled(false);
389     expected = String.format(
390             "domain\tattribute|CSQ:AF|%s|%s|noValueMax|abso|12.0|25.0|above|12.5",
391             greenHex, redHex);
392     assertEquals(expected, fc.toJalviewFormat("domain"));
393   }
394
395   /**
396    * Test parsing of feature colours from Jalview features file format
397    */
398   @Test(groups = { "Functional" })
399   public void testParseJalviewFeatureColour()
400   {
401     /*
402      * simple colour by name
403      */
404     FeatureColourI fc = FeatureColour.parseJalviewFeatureColour("red");
405     assertTrue(fc.isSimpleColour());
406     assertEquals(Color.RED, fc.getColour());
407
408     /*
409      * simple colour by hex code
410      */
411     fc = FeatureColour
412             .parseJalviewFeatureColour(Format.getHexString(Color.RED));
413     assertTrue(fc.isSimpleColour());
414     assertEquals(Color.RED, fc.getColour());
415
416     /*
417      * simple colour by rgb triplet
418      */
419     fc = FeatureColour.parseJalviewFeatureColour("255,0,0");
420     assertTrue(fc.isSimpleColour());
421     assertEquals(Color.RED, fc.getColour());
422
423     /*
424      * malformed colour
425      */
426     try
427     {
428       fc = FeatureColour.parseJalviewFeatureColour("oops");
429       fail("expected exception");
430     } catch (IllegalArgumentException e)
431     {
432       assertEquals("Invalid colour descriptor: oops", e.getMessage());
433     }
434
435     /*
436      * colour by label (no threshold)
437      */
438     fc = FeatureColour.parseJalviewFeatureColour("label");
439     assertTrue(fc.isColourByLabel());
440     assertFalse(fc.hasThreshold());
441
442     /*
443      * colour by label (with threshold)
444      */
445     fc = FeatureColour
446             .parseJalviewFeatureColour("label|||0.0|0.0|above|12.0");
447     assertTrue(fc.isColourByLabel());
448     assertTrue(fc.isAboveThreshold());
449     assertEquals(12.0f, fc.getThreshold());
450
451     /*
452      * colour by attribute text (no threshold)
453      */
454     fc = FeatureColour.parseJalviewFeatureColour("attribute|CLIN_SIG");
455     assertTrue(fc.isColourByAttribute());
456     assertTrue(fc.isColourByLabel());
457     assertFalse(fc.hasThreshold());
458     assertArrayEquals(new String[] { "CLIN_SIG" }, fc.getAttributeName());
459
460     /*
461      * colour by attributes text (with score threshold)
462      */
463     fc = FeatureColour.parseJalviewFeatureColour(
464             "attribute|CSQ:Consequence|||0.0|0.0|above|12.0");
465     assertTrue(fc.isColourByLabel());
466     assertTrue(fc.isColourByAttribute());
467     assertArrayEquals(new String[] { "CSQ", "Consequence" },
468             fc.getAttributeName());
469     assertTrue(fc.isAboveThreshold());
470     assertEquals(12.0f, fc.getThreshold());
471
472     /*
473      * graduated colour by score (with colour names) (no threshold)
474      */
475     fc = FeatureColour.parseJalviewFeatureColour("red|green|10.0|20.0");
476     assertTrue(fc.isGraduatedColour());
477     assertFalse(fc.hasThreshold());
478     assertEquals(Color.RED, fc.getMinColour());
479     assertEquals(Color.GREEN, fc.getMaxColour());
480     assertEquals(Color.RED, fc.getNoColour());
481     assertEquals(10f, fc.getMin());
482     assertEquals(20f, fc.getMax());
483     assertTrue(fc.isAutoScaled());
484
485     /*
486      * the same, with 'no value colour' specified as max
487      */
488     fc = FeatureColour
489             .parseJalviewFeatureColour("red|green|novaluemax|10.0|20.0");
490     assertEquals(Color.RED, fc.getMinColour());
491     assertEquals(Color.GREEN, fc.getMaxColour());
492     assertEquals(Color.GREEN, fc.getNoColour());
493     assertEquals(10f, fc.getMin());
494     assertEquals(20f, fc.getMax());
495
496     /*
497      * the same, with 'no value colour' specified as min
498      */
499     fc = FeatureColour
500             .parseJalviewFeatureColour("red|green|novalueMin|10.0|20.0");
501     assertEquals(Color.RED, fc.getMinColour());
502     assertEquals(Color.GREEN, fc.getMaxColour());
503     assertEquals(Color.RED, fc.getNoColour());
504     assertEquals(10f, fc.getMin());
505     assertEquals(20f, fc.getMax());
506
507     /*
508      * the same, with 'no value colour' specified as none
509      */
510     fc = FeatureColour
511             .parseJalviewFeatureColour("red|green|novaluenone|10.0|20.0");
512     assertEquals(Color.RED, fc.getMinColour());
513     assertEquals(Color.GREEN, fc.getMaxColour());
514     assertNull(fc.getNoColour());
515     assertEquals(10f, fc.getMin());
516     assertEquals(20f, fc.getMax());
517
518     /*
519      * the same, with invalid 'no value colour'
520      */
521     try
522     {
523       fc = FeatureColour
524               .parseJalviewFeatureColour("red|green|blue|10.0|20.0");
525       fail("expected exception");
526     } catch (IllegalArgumentException e)
527     {
528       assertEquals(
529               "Couldn't parse the minimum value for graduated colour ('blue')",
530               e.getMessage());
531     }
532
533     /*
534      * graduated colour (explicitly by 'score') (no threshold)
535      */
536     fc = FeatureColour
537             .parseJalviewFeatureColour("Score|red|green|10.0|20.0");
538     assertTrue(fc.isGraduatedColour());
539     assertFalse(fc.hasThreshold());
540     assertEquals(Color.RED, fc.getMinColour());
541     assertEquals(Color.GREEN, fc.getMaxColour());
542     assertEquals(10f, fc.getMin());
543     assertEquals(20f, fc.getMax());
544     assertTrue(fc.isAutoScaled());
545
546     /*
547      * graduated colour by attribute (no threshold)
548      */
549     fc = FeatureColour
550             .parseJalviewFeatureColour("attribute|AF|red|green|10.0|20.0");
551     assertTrue(fc.isGraduatedColour());
552     assertTrue(fc.isColourByAttribute());
553     assertArrayEquals(new String[] { "AF" }, fc.getAttributeName());
554     assertFalse(fc.hasThreshold());
555     assertEquals(Color.RED, fc.getMinColour());
556     assertEquals(Color.GREEN, fc.getMaxColour());
557     assertEquals(10f, fc.getMin());
558     assertEquals(20f, fc.getMax());
559     assertTrue(fc.isAutoScaled());
560
561     /*
562      * graduated colour by score (colours by hex code) (above threshold)
563      */
564     String descriptor = String.format("%s|%s|10.0|20.0|above|15",
565             Format.getHexString(Color.RED),
566             Format.getHexString(Color.GREEN));
567     fc = FeatureColour.parseJalviewFeatureColour(descriptor);
568     assertTrue(fc.isGraduatedColour());
569     assertTrue(fc.hasThreshold());
570     assertTrue(fc.isAboveThreshold());
571     assertEquals(15f, fc.getThreshold());
572     assertEquals(Color.RED, fc.getMinColour());
573     assertEquals(Color.GREEN, fc.getMaxColour());
574     assertEquals(10f, fc.getMin());
575     assertEquals(20f, fc.getMax());
576     assertTrue(fc.isAutoScaled());
577
578     /*
579      * graduated colour by attributes (below threshold)
580      */
581     fc = FeatureColour.parseJalviewFeatureColour(
582             "attribute|CSQ:AF|red|green|10.0|20.0|below|13");
583     assertTrue(fc.isGraduatedColour());
584     assertTrue(fc.isColourByAttribute());
585     assertArrayEquals(new String[] { "CSQ", "AF" }, fc.getAttributeName());
586     assertTrue(fc.hasThreshold());
587     assertTrue(fc.isBelowThreshold());
588     assertEquals(13f, fc.getThreshold());
589     assertEquals(Color.RED, fc.getMinColour());
590     assertEquals(Color.GREEN, fc.getMaxColour());
591     assertEquals(10f, fc.getMin());
592     assertEquals(20f, fc.getMax());
593     assertTrue(fc.isAutoScaled());
594
595     /*
596      * graduated colour (by RGB triplet) (below threshold), absolute scale
597      */
598     descriptor = "255,0,0|0,255,0|abso|10.0|20.0|below|15";
599     fc = FeatureColour.parseJalviewFeatureColour(descriptor);
600     assertTrue(fc.isGraduatedColour());
601     assertFalse(fc.isAutoScaled());
602     assertTrue(fc.hasThreshold());
603     assertTrue(fc.isBelowThreshold());
604     assertEquals(15f, fc.getThreshold());
605     assertEquals(Color.RED, fc.getMinColour());
606     assertEquals(Color.GREEN, fc.getMaxColour());
607     assertEquals(10f, fc.getMin());
608     assertEquals(20f, fc.getMax());
609
610     descriptor = "blue|255,0,255|absolute|20.0|95.0|below|66.0";
611     fc = FeatureColour.parseJalviewFeatureColour(descriptor);
612     assertTrue(fc.isGraduatedColour());
613   }
614
615   @Test(groups = { "Functional" })
616   public void testGetColor_colourByAttributeText()
617   {
618     FeatureColour fc = new FeatureColour();
619     fc.setColourByLabel(true);
620     fc.setAttributeName("consequence");
621     SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 1f,
622             null);
623
624     /*
625      * if feature has no such attribute, use 'no value' colour
626      */
627     assertEquals(FeatureColour.DEFAULT_NO_COLOUR, fc.getColor(sf));
628
629     /*
630      * if feature has attribute, generate colour from value
631      */
632     sf.setValue("consequence", "benign");
633     Color expected = ColorUtils.createColourFromName("benign");
634     assertEquals(expected, fc.getColor(sf));
635   }
636
637   @Test(groups = { "Functional" })
638   public void testGetColor_GraduatedByAttributeValue()
639   {
640     /*
641      * graduated colour based on attribute value for AF
642      * given a min-max range of 0-100
643      */
644     FeatureColour fc = new FeatureColour(Color.white,
645             new Color(50, 100, 150), new Color(150, 200, 250), Color.yellow,
646             0f, 100f);
647     String attName = "AF";
648     fc.setAttributeName(attName);
649
650     /*
651      * first case: feature lacks the attribute - use 'no value' colour
652      */
653     SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 75f,
654             null);
655     assertEquals(Color.yellow, fc.getColor(sf));
656
657     /*
658      * second case: attribute present but not numeric - treat as if absent
659      */
660     sf.setValue(attName, "twelve");
661     assertEquals(Color.yellow, fc.getColor(sf));
662
663     /*
664      * third case: valid attribute value
665      */
666     sf.setValue(attName, "20.0");
667     Color expected = new Color(70, 120, 170);
668     assertEquals(expected, fc.getColor(sf));
669   }
670
671   @Test(groups = { "Functional" })
672   public void testIsOutwithThreshold()
673   {
674     FeatureColourI fc = new FeatureColour(Color.red);
675     SequenceFeature sf = new SequenceFeature("METAL", "desc", 10, 12, 1.2f,
676             "grp");
677     assertFalse(fc.isOutwithThreshold(null));
678     assertFalse(fc.isOutwithThreshold(sf));
679
680     fc = new FeatureColour(null, Color.white, Color.black, Color.green, 0f,
681             10f);
682     assertFalse(fc.isOutwithThreshold(sf)); // no threshold
683
684     fc.setAboveThreshold(true);
685     fc.setThreshold(1f);
686     assertFalse(fc.isOutwithThreshold(sf)); // feature score 1.2 is above 1
687
688     fc.setThreshold(2f);
689     assertTrue(fc.isOutwithThreshold(sf)); // feature score 1.2 is not above 2
690
691     fc.setBelowThreshold(true);
692     assertFalse(fc.isOutwithThreshold(sf)); // feature score 1.2 is below 2
693
694     fc.setThreshold(1f);
695     assertTrue(fc.isOutwithThreshold(sf)); // feature score 1.2 is not below 1
696
697     /*
698      * with attribute value threshold
699      */
700     fc.setAttributeName("AC");
701     assertFalse(fc.isOutwithThreshold(sf)); // missing attribute AC is ignored
702
703     sf.setValue("AC", "-1");
704     assertFalse(fc.isOutwithThreshold(sf)); // value -1 is below 1
705
706     sf.setValue("AC", "1");
707     assertTrue(fc.isOutwithThreshold(sf)); // value 1 is not below 1
708
709     sf.setValue("AC", "junk");
710     assertFalse(fc.isOutwithThreshold(sf)); // bad value is ignored
711   }
712
713   /**
714    * Test description of feature colour suitable for a tooltip
715    */
716   @Test(groups = { "Functional" })
717   public void testGetDescription()
718   {
719     /*
720      * plain colour
721      */
722     FeatureColour fc = new FeatureColour(Color.RED);
723     assertEquals(
724             String.format("r=%d,g=%d,b=%d", Color.RED.getRed(),
725                     Color.red.getGreen(), Color.red.getBlue()),
726             fc.getDescription());
727
728     /*
729      * colour by label (no threshold)
730      */
731     fc = new FeatureColour();
732     fc.setColourByLabel(true);
733     assertEquals("By Label", fc.getDescription());
734
735     /*
736      * colour by attribute text (no threshold)
737      */
738     fc = new FeatureColour();
739     fc.setColourByLabel(true);
740     fc.setAttributeName("CLIN_SIG");
741     assertEquals("By CLIN_SIG", fc.getDescription());
742
743     /*
744      * colour by label (above score threshold) 
745      */
746     fc = new FeatureColour();
747     fc.setColourByLabel(true);
748     fc.setAutoScaled(false);
749     fc.setThreshold(12.5f);
750     fc.setAboveThreshold(true);
751     assertEquals("By Label (Score > 12.5)", fc.getDescription());
752
753     /*
754      * colour by label (below score threshold)
755      */
756     fc.setBelowThreshold(true);
757     assertEquals("By Label (Score < 12.5)", fc.getDescription());
758
759     /*
760      * colour by attributes text (below score threshold)
761      */
762     fc.setBelowThreshold(true);
763     fc.setAttributeName("CSQ", "Consequence");
764     assertEquals("By CSQ:Consequence (Score < 12.5)", fc.getDescription());
765
766     /*
767      * graduated colour by score, no threshold
768      */
769     fc = new FeatureColour(null, Color.GREEN, Color.RED, null, 12f, 25f);
770     assertEquals("By Score", fc.getDescription());
771
772     /*
773      * graduated colour by score, below threshold
774      */
775     fc.setThreshold(12.5f);
776     fc.setBelowThreshold(true);
777     assertEquals("By Score (< 12.5)", fc.getDescription());
778
779     /*
780      * graduated colour by score, above threshold
781      */
782     fc.setThreshold(12.5f);
783     fc.setAboveThreshold(true);
784     fc.setAutoScaled(false);
785     assertEquals("By Score (> 12.5)", fc.getDescription());
786
787     /*
788      * graduated colour by attribute, no threshold
789      */
790     fc.setAttributeName("CSQ", "AF");
791     fc.setAboveThreshold(false);
792     fc.setAutoScaled(false);
793     assertEquals("By CSQ:AF", fc.getDescription());
794
795     /*
796      * graduated colour by attribute, above threshold
797      */
798     fc.setAboveThreshold(true);
799     fc.setAutoScaled(false);
800     assertEquals("By CSQ:AF (> 12.5)", fc.getDescription());
801   }
802 }