2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
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.
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.
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.
21 package jalview.schemes;
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;
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;
36 import java.awt.Color;
38 import org.testng.annotations.BeforeClass;
39 import org.testng.annotations.Test;
41 import junit.extensions.PA;
43 public class FeatureColourTest
46 @BeforeClass(alwaysRun = true)
47 public void setUpJvOptionPane()
49 JvOptionPane.setInteractiveMode(false);
50 JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
53 @Test(groups = { "Functional" })
54 public void testCopyConstructor()
59 FeatureColour fc = new FeatureColour(Color.RED);
60 FeatureColour fc1 = new FeatureColour(fc);
61 assertTrue(fc1.getColour().equals(Color.RED));
62 assertFalse(fc1.isGraduatedColour());
63 assertFalse(fc1.isColourByLabel());
64 assertFalse(fc1.isColourByAttribute());
65 assertNull(fc1.getAttributeName());
70 fc = new FeatureColour(Color.gray, Color.black, 10f, 20f);
71 fc.setAboveThreshold(true);
73 fc1 = new FeatureColour(fc);
74 assertTrue(fc1.isGraduatedColour());
75 assertFalse(fc1.isColourByLabel());
76 assertTrue(fc1.isAboveThreshold());
77 assertFalse(fc1.isColourByAttribute());
78 assertNull(fc1.getAttributeName());
79 assertEquals(12f, fc1.getThreshold());
80 assertEquals(Color.gray, fc1.getMinColour());
81 assertEquals(Color.black, fc1.getMaxColour());
82 assertEquals(Color.gray, fc1.getNoColour());
83 assertEquals(10f, fc1.getMin());
84 assertEquals(20f, fc1.getMax());
87 * min-max-noValue colour
89 fc = new FeatureColour(Color.gray, Color.black, Color.green, 10f, 20f);
90 fc.setAboveThreshold(true);
92 fc1 = new FeatureColour(fc);
93 assertTrue(fc1.isGraduatedColour());
94 assertFalse(fc1.isColourByLabel());
95 assertFalse(fc1.isColourByAttribute());
96 assertNull(fc1.getAttributeName());
97 assertTrue(fc1.isAboveThreshold());
98 assertEquals(12f, fc1.getThreshold());
99 assertEquals(Color.gray, fc1.getMinColour());
100 assertEquals(Color.black, fc1.getMaxColour());
101 assertEquals(Color.green, fc1.getNoColour());
102 assertEquals(10f, fc1.getMin());
103 assertEquals(20f, fc1.getMax());
108 fc = new FeatureColour();
109 fc.setColourByLabel(true);
110 fc1 = new FeatureColour(fc);
111 assertTrue(fc1.isColourByLabel());
112 assertFalse(fc1.isGraduatedColour());
113 assertFalse(fc1.isColourByAttribute());
114 assertNull(fc1.getAttributeName());
117 * colour by attribute (label)
119 fc = new FeatureColour();
120 fc.setColourByLabel(true);
121 fc.setAttributeName("AF");
122 fc1 = new FeatureColour(fc);
123 assertTrue(fc1.isColourByLabel());
124 assertFalse(fc1.isGraduatedColour());
125 assertTrue(fc1.isColourByAttribute());
126 assertArrayEquals(new String[] { "AF" }, fc1.getAttributeName());
129 * colour by attribute (value)
131 fc = new FeatureColour(Color.gray, Color.black, Color.green, 10f, 20f);
132 fc.setAboveThreshold(true);
133 fc.setThreshold(12f);
134 fc.setAttributeName("AF");
135 fc1 = new FeatureColour(fc);
136 assertTrue(fc1.isGraduatedColour());
137 assertFalse(fc1.isColourByLabel());
138 assertTrue(fc1.isColourByAttribute());
139 assertArrayEquals(new String[] { "AF" }, fc1.getAttributeName());
140 assertTrue(fc1.isAboveThreshold());
141 assertEquals(12f, fc1.getThreshold());
142 assertEquals(Color.gray, fc1.getMinColour());
143 assertEquals(Color.black, fc1.getMaxColour());
144 assertEquals(Color.green, fc1.getNoColour());
145 assertEquals(10f, fc1.getMin());
146 assertEquals(20f, fc1.getMax());
149 @Test(groups = { "Functional" })
150 public void testCopyConstructor_minMax()
155 FeatureColour fc = new FeatureColour(Color.BLUE, Color.RED, 1f, 5f);
156 assertTrue(fc.isGraduatedColour());
157 assertFalse(fc.isColourByLabel());
158 assertFalse(fc.isColourByAttribute());
159 assertNull(fc.getAttributeName());
160 assertEquals(1f, fc.getMin());
161 assertEquals(5f, fc.getMax());
164 * update min-max bounds
166 FeatureColour fc1 = new FeatureColour(fc, 2f, 6f);
167 assertTrue(fc1.isGraduatedColour());
168 assertFalse(fc1.isColourByLabel());
169 assertFalse(fc1.isColourByAttribute());
170 assertNull(fc1.getAttributeName());
171 assertEquals(2f, fc1.getMin());
172 assertEquals(6f, fc1.getMax());
173 assertFalse((boolean) PA.getValue(fc1, "isHighToLow"));
176 * update min-max bounds - high to low
178 fc1 = new FeatureColour(fc, 23f, 16f);
179 assertTrue(fc1.isGraduatedColour());
180 assertFalse(fc1.isColourByLabel());
181 assertFalse(fc1.isColourByAttribute());
182 assertNull(fc1.getAttributeName());
183 assertEquals(23f, fc1.getMin());
184 assertEquals(16f, fc1.getMax());
185 assertTrue((boolean) PA.getValue(fc1, "isHighToLow"));
188 * graduated colour by attribute
190 fc1.setAttributeName("AF");
191 fc1 = new FeatureColour(fc1, 13f, 36f);
192 assertTrue(fc1.isGraduatedColour());
193 assertFalse(fc1.isColourByLabel());
194 assertTrue(fc1.isColourByAttribute());
195 assertArrayEquals(new String[] { "AF" }, fc1.getAttributeName());
196 assertEquals(13f, fc1.getMin());
197 assertEquals(36f, fc1.getMax());
198 assertFalse((boolean) PA.getValue(fc1, "isHighToLow"));
203 fc = new FeatureColour(Color.BLUE, Color.RED, 1f, 5f);
204 fc.setColourByLabel(true);
205 assertFalse(fc.isGraduatedColour());
206 assertTrue(fc.isColourByLabel());
207 assertFalse(fc.isColourByAttribute());
208 assertNull(fc.getAttributeName());
209 assertEquals(1f, fc.getMin());
210 assertEquals(5f, fc.getMax());
213 * update min-max bounds
215 fc1 = new FeatureColour(fc, 2f, 6f);
216 assertFalse(fc1.isGraduatedColour());
217 assertTrue(fc1.isColourByLabel());
218 assertFalse(fc1.isColourByAttribute());
219 assertNull(fc1.getAttributeName());
220 assertEquals(2f, fc1.getMin());
221 assertEquals(6f, fc1.getMax());
224 * colour by attribute text
226 fc1.setAttributeName("AC");
227 fc1 = new FeatureColour(fc1, 13f, 36f);
228 assertFalse(fc1.isGraduatedColour());
229 assertTrue(fc1.isColourByLabel());
230 assertTrue(fc1.isColourByAttribute());
231 assertArrayEquals(new String[] { "AC" }, fc1.getAttributeName());
232 assertEquals(13f, fc1.getMin());
233 assertEquals(36f, fc1.getMax());
236 @Test(groups = { "Functional" })
237 public void testGetColor_simpleColour()
239 FeatureColour fc = new FeatureColour(Color.RED);
240 assertEquals(Color.RED,
241 fc.getColor(new SequenceFeature("Cath", "", 1, 2, 0f, null)));
244 @Test(groups = { "Functional" })
245 public void testGetColor_colourByLabel()
247 FeatureColour fc = new FeatureColour();
248 fc.setColourByLabel(true);
249 SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 1f,
251 Color expected = ColorUtils.createColourFromName("desc");
252 assertEquals(expected, fc.getColor(sf));
255 @Test(groups = { "Functional" })
256 public void testGetColor_Graduated()
259 * graduated colour from
261 * gray(128, 128, 128) to red(255, 0, 0)
263 FeatureColour fc = new FeatureColour(Color.GRAY, Color.RED, 0f, 100f);
264 // feature score is 75 which is 3/4 of the way from GRAY to RED
265 SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 75f,
267 // the colour gradient is computed in float values from 0-1 (where 1 == 255)
268 float red = 128 / 255f + 3 / 4f * (255 - 128) / 255f;
269 float green = 128 / 255f + 3 / 4f * (0 - 128) / 255f;
270 float blue = 128 / 255f + 3 / 4f * (0 - 128) / 255f;
271 Color expected = new Color(red, green, blue);
272 assertEquals(expected, fc.getColor(sf));
275 @Test(groups = { "Functional" })
276 public void testGetColor_aboveBelowThreshold()
278 // gradient from [50, 150] from WHITE(255, 255, 255) to BLACK(0, 0, 0)
279 FeatureColour fc = new FeatureColour(Color.WHITE, Color.BLACK, 50f,
281 SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 70f,
285 * feature with score of Float.NaN is always assigned minimum colour
287 SequenceFeature sf2 = new SequenceFeature("type", "desc", 0, 20,
290 fc.setThreshold(100f); // ignore for now
291 assertEquals(new Color(204, 204, 204), fc.getColor(sf));
292 assertEquals(Color.white, fc.getColor(sf2));
294 fc.setAboveThreshold(true); // feature lies below threshold
295 assertNull(fc.getColor(sf));
296 assertEquals(Color.white, fc.getColor(sf2));
298 fc.setBelowThreshold(true);
299 fc.setThreshold(70f);
300 assertNull(fc.getColor(sf)); // feature score == threshold - hidden
301 assertEquals(Color.white, fc.getColor(sf2));
302 fc.setThreshold(69f);
303 assertNull(fc.getColor(sf)); // feature score > threshold - hidden
304 assertEquals(Color.white, fc.getColor(sf2));
308 * Test output of feature colours to Jalview features file format
310 @Test(groups = { "Functional" })
311 public void testToJalviewFormat()
314 * plain colour - to RGB hex code
316 FeatureColour fc = new FeatureColour(Color.RED);
317 String redHex = Format.getHexString(Color.RED);
318 String hexColour = redHex;
319 assertEquals("domain\t" + hexColour, fc.toJalviewFormat("domain"));
322 * colour by label (no threshold)
324 fc = new FeatureColour();
325 fc.setColourByLabel(true);
326 assertEquals("domain\tlabel", fc.toJalviewFormat("domain"));
329 * colour by attribute text (no threshold)
331 fc = new FeatureColour();
332 fc.setColourByLabel(true);
333 fc.setAttributeName("CLIN_SIG");
334 assertEquals("domain\tattribute|CLIN_SIG", fc.toJalviewFormat("domain"));
337 * colour by label (autoscaled) (an odd state you can reach by selecting
338 * 'above threshold', then deselecting 'threshold is min/max' then 'colour
341 fc.setAttributeName((String[]) null);
342 fc.setAutoScaled(true);
343 assertEquals("domain\tlabel", fc.toJalviewFormat("domain"));
346 * colour by label (above threshold)
348 fc.setAutoScaled(false);
349 fc.setThreshold(12.5f);
350 fc.setAboveThreshold(true);
351 // min/max values are output though not used by this scheme
352 assertEquals("domain\tlabel|||0.0|0.0|above|12.5",
353 fc.toJalviewFormat("domain"));
356 * colour by label (below threshold)
358 fc.setBelowThreshold(true);
359 assertEquals("domain\tlabel|||0.0|0.0|below|12.5",
360 fc.toJalviewFormat("domain"));
363 * colour by attributes text (below threshold)
365 fc.setBelowThreshold(true);
366 fc.setAttributeName("CSQ", "Consequence");
367 assertEquals("domain\tattribute|CSQ:Consequence|||0.0|0.0|below|12.5",
368 fc.toJalviewFormat("domain"));
371 * graduated colour by score, no threshold
372 * - default constructor sets noValueColor = minColor
374 fc = new FeatureColour(Color.GREEN, Color.RED, 12f, 25f);
375 String greenHex = Format.getHexString(Color.GREEN);
376 String expected = String.format(
377 "domain\tscore|%s|%s|noValueMin|abso|12.0|25.0|none", greenHex,
379 assertEquals(expected, fc.toJalviewFormat("domain"));
382 * graduated colour by score, no threshold, no value gets min colour
384 fc = new FeatureColour(Color.GREEN, Color.RED, Color.GREEN, 12f, 25f);
385 expected = String.format(
386 "domain\tscore|%s|%s|noValueMin|abso|12.0|25.0|none", greenHex,
388 assertEquals(expected, fc.toJalviewFormat("domain"));
391 * graduated colour by score, no threshold, no value gets max colour
393 fc = new FeatureColour(Color.GREEN, Color.RED, Color.RED, 12f, 25f);
394 expected = String.format(
395 "domain\tscore|%s|%s|noValueMax|abso|12.0|25.0|none", greenHex,
397 assertEquals(expected, fc.toJalviewFormat("domain"));
400 * colour ranges over the actual score ranges (not min/max)
402 fc.setAutoScaled(true);
403 expected = String.format(
404 "domain\tscore|%s|%s|noValueMax|12.0|25.0|none", greenHex,
406 assertEquals(expected, fc.toJalviewFormat("domain"));
409 * graduated colour by score, below threshold
411 fc.setThreshold(12.5f);
412 fc.setBelowThreshold(true);
413 expected = String.format(
414 "domain\tscore|%s|%s|noValueMax|12.0|25.0|below|12.5",
416 assertEquals(expected, fc.toJalviewFormat("domain"));
419 * graduated colour by score, above threshold
421 fc.setThreshold(12.5f);
422 fc.setAboveThreshold(true);
423 fc.setAutoScaled(false);
424 expected = String.format(
425 "domain\tscore|%s|%s|noValueMax|abso|12.0|25.0|above|12.5",
427 assertEquals(expected, fc.toJalviewFormat("domain"));
430 * graduated colour by attribute, above threshold
432 fc.setAttributeName("CSQ", "AF");
433 fc.setAboveThreshold(true);
434 fc.setAutoScaled(false);
435 expected = String.format(
436 "domain\tattribute|CSQ:AF|%s|%s|noValueMax|abso|12.0|25.0|above|12.5",
438 assertEquals(expected, fc.toJalviewFormat("domain"));
442 * Test parsing of feature colours from Jalview features file format
444 @Test(groups = { "Functional" })
445 public void testParseJalviewFeatureColour()
448 * simple colour by name
450 FeatureColourI fc = FeatureColour.parseJalviewFeatureColour("red");
451 assertTrue(fc.isSimpleColour());
452 assertEquals(Color.RED, fc.getColour());
455 * simple colour by hex code
457 fc = FeatureColour.parseJalviewFeatureColour(Format
458 .getHexString(Color.RED));
459 assertTrue(fc.isSimpleColour());
460 assertEquals(Color.RED, fc.getColour());
463 * simple colour by rgb triplet
465 fc = FeatureColour.parseJalviewFeatureColour("255,0,0");
466 assertTrue(fc.isSimpleColour());
467 assertEquals(Color.RED, fc.getColour());
474 fc = FeatureColour.parseJalviewFeatureColour("oops");
475 fail("expected exception");
476 } catch (IllegalArgumentException e)
478 assertEquals("Invalid colour descriptor: oops", e.getMessage());
482 * colour by label (no threshold)
484 fc = FeatureColour.parseJalviewFeatureColour("label");
485 assertTrue(fc.isColourByLabel());
486 assertFalse(fc.hasThreshold());
489 * colour by label (with threshold)
492 .parseJalviewFeatureColour("label|||0.0|0.0|above|12.0");
493 assertTrue(fc.isColourByLabel());
494 assertTrue(fc.isAboveThreshold());
495 assertEquals(12.0f, fc.getThreshold());
498 * colour by attribute text (no threshold)
500 fc = FeatureColour.parseJalviewFeatureColour("attribute|CLIN_SIG");
501 assertTrue(fc.isColourByAttribute());
502 assertTrue(fc.isColourByLabel());
503 assertFalse(fc.hasThreshold());
504 assertArrayEquals(new String[] { "CLIN_SIG" }, fc.getAttributeName());
507 * colour by attributes text (with score threshold)
509 fc = FeatureColour.parseJalviewFeatureColour(
510 "attribute|CSQ:Consequence|||0.0|0.0|above|12.0");
511 assertTrue(fc.isColourByLabel());
512 assertTrue(fc.isColourByAttribute());
513 assertArrayEquals(new String[] { "CSQ", "Consequence" },
514 fc.getAttributeName());
515 assertTrue(fc.isAboveThreshold());
516 assertEquals(12.0f, fc.getThreshold());
519 * graduated colour by score (with colour names) (no threshold)
521 fc = FeatureColour.parseJalviewFeatureColour("red|green|10.0|20.0");
522 assertTrue(fc.isGraduatedColour());
523 assertFalse(fc.hasThreshold());
524 assertEquals(Color.RED, fc.getMinColour());
525 assertEquals(Color.GREEN, fc.getMaxColour());
526 assertEquals(Color.RED, fc.getNoColour());
527 assertEquals(10f, fc.getMin());
528 assertEquals(20f, fc.getMax());
529 assertTrue(fc.isAutoScaled());
532 * the same, with 'no value colour' specified as max
535 .parseJalviewFeatureColour("red|green|novaluemax|10.0|20.0");
536 assertEquals(Color.RED, fc.getMinColour());
537 assertEquals(Color.GREEN, fc.getMaxColour());
538 assertEquals(Color.GREEN, fc.getNoColour());
539 assertEquals(10f, fc.getMin());
540 assertEquals(20f, fc.getMax());
543 * the same, with 'no value colour' specified as min
546 .parseJalviewFeatureColour("red|green|novalueMin|10.0|20.0");
547 assertEquals(Color.RED, fc.getMinColour());
548 assertEquals(Color.GREEN, fc.getMaxColour());
549 assertEquals(Color.RED, fc.getNoColour());
550 assertEquals(10f, fc.getMin());
551 assertEquals(20f, fc.getMax());
554 * the same, with 'no value colour' specified as none
557 .parseJalviewFeatureColour("red|green|novaluenone|10.0|20.0");
558 assertEquals(Color.RED, fc.getMinColour());
559 assertEquals(Color.GREEN, fc.getMaxColour());
560 assertNull(fc.getNoColour());
561 assertEquals(10f, fc.getMin());
562 assertEquals(20f, fc.getMax());
565 * the same, with invalid 'no value colour'
570 .parseJalviewFeatureColour("red|green|blue|10.0|20.0");
571 fail("expected exception");
572 } catch (IllegalArgumentException e)
575 "Couldn't parse the minimum value for graduated colour ('blue')",
580 * graduated colour (explicitly by 'score') (no threshold)
583 .parseJalviewFeatureColour("Score|red|green|10.0|20.0");
584 assertTrue(fc.isGraduatedColour());
585 assertFalse(fc.hasThreshold());
586 assertEquals(Color.RED, fc.getMinColour());
587 assertEquals(Color.GREEN, fc.getMaxColour());
588 assertEquals(10f, fc.getMin());
589 assertEquals(20f, fc.getMax());
590 assertTrue(fc.isAutoScaled());
593 * graduated colour by attribute (no threshold)
596 .parseJalviewFeatureColour("attribute|AF|red|green|10.0|20.0");
597 assertTrue(fc.isGraduatedColour());
598 assertTrue(fc.isColourByAttribute());
599 assertArrayEquals(new String[] { "AF" }, fc.getAttributeName());
600 assertFalse(fc.hasThreshold());
601 assertEquals(Color.RED, fc.getMinColour());
602 assertEquals(Color.GREEN, fc.getMaxColour());
603 assertEquals(10f, fc.getMin());
604 assertEquals(20f, fc.getMax());
605 assertTrue(fc.isAutoScaled());
608 * graduated colour by score (colours by hex code) (above threshold)
610 String descriptor = String.format("%s|%s|10.0|20.0|above|15",
611 Format.getHexString(Color.RED),
612 Format.getHexString(Color.GREEN));
613 fc = FeatureColour.parseJalviewFeatureColour(descriptor);
614 assertTrue(fc.isGraduatedColour());
615 assertTrue(fc.hasThreshold());
616 assertTrue(fc.isAboveThreshold());
617 assertEquals(15f, fc.getThreshold());
618 assertEquals(Color.RED, fc.getMinColour());
619 assertEquals(Color.GREEN, fc.getMaxColour());
620 assertEquals(10f, fc.getMin());
621 assertEquals(20f, fc.getMax());
622 assertTrue(fc.isAutoScaled());
625 * graduated colour by attributes (below threshold)
627 fc = FeatureColour.parseJalviewFeatureColour(
628 "attribute|CSQ:AF|red|green|10.0|20.0|below|13");
629 assertTrue(fc.isGraduatedColour());
630 assertTrue(fc.isColourByAttribute());
631 assertArrayEquals(new String[] { "CSQ", "AF" }, fc.getAttributeName());
632 assertTrue(fc.hasThreshold());
633 assertTrue(fc.isBelowThreshold());
634 assertEquals(13f, fc.getThreshold());
635 assertEquals(Color.RED, fc.getMinColour());
636 assertEquals(Color.GREEN, fc.getMaxColour());
637 assertEquals(10f, fc.getMin());
638 assertEquals(20f, fc.getMax());
639 assertTrue(fc.isAutoScaled());
642 * graduated colour (by RGB triplet) (below threshold), absolute scale
644 descriptor = "255,0,0|0,255,0|abso|10.0|20.0|below|15";
645 fc = FeatureColour.parseJalviewFeatureColour(descriptor);
646 assertTrue(fc.isGraduatedColour());
647 assertFalse(fc.isAutoScaled());
648 assertTrue(fc.hasThreshold());
649 assertTrue(fc.isBelowThreshold());
650 assertEquals(15f, fc.getThreshold());
651 assertEquals(Color.RED, fc.getMinColour());
652 assertEquals(Color.GREEN, fc.getMaxColour());
653 assertEquals(10f, fc.getMin());
654 assertEquals(20f, fc.getMax());
656 descriptor = "blue|255,0,255|absolute|20.0|95.0|below|66.0";
657 fc = FeatureColour.parseJalviewFeatureColour(descriptor);
658 assertTrue(fc.isGraduatedColour());
661 @Test(groups = { "Functional" })
662 public void testGetColor_colourByAttributeText()
664 FeatureColour fc = new FeatureColour();
665 fc.setColourByLabel(true);
666 fc.setAttributeName("consequence");
667 SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 1f,
671 * if feature has no such attribute, use 'no value' colour
673 assertEquals(FeatureColour.DEFAULT_NO_COLOUR, fc.getColor(sf));
676 * if feature has attribute, generate colour from value
678 sf.setValue("consequence", "benign");
679 Color expected = ColorUtils.createColourFromName("benign");
680 assertEquals(expected, fc.getColor(sf));
683 @Test(groups = { "Functional" })
684 public void testGetColor_GraduatedByAttributeValue()
687 * graduated colour based on attribute value for AF
688 * given a min-max range of 0-100
690 FeatureColour fc = new FeatureColour(new Color(50, 100, 150),
691 new Color(150, 200, 250), Color.yellow, 0f, 100f);
692 String attName = "AF";
693 fc.setAttributeName(attName);
696 * first case: feature lacks the attribute - use 'no value' colour
698 SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 75f,
700 assertEquals(Color.yellow, fc.getColor(sf));
703 * second case: attribute present but not numeric - treat as if absent
705 sf.setValue(attName, "twelve");
706 assertEquals(Color.yellow, fc.getColor(sf));
709 * third case: valid attribute value
711 sf.setValue(attName, "20.0");
712 Color expected = new Color(70, 120, 170);
713 assertEquals(expected, fc.getColor(sf));