JAL-2438 unit test, fixes, Javadoc updates
[jalview.git] / test / jalview / renderer / seqfeatures / FeatureColourFinderTest.java
1 package jalview.renderer.seqfeatures;
2
3 import static org.testng.Assert.assertEquals;
4
5 import jalview.api.FeatureColourI;
6 import jalview.datamodel.SequenceFeature;
7 import jalview.datamodel.SequenceI;
8 import jalview.gui.AlignFrame;
9 import jalview.gui.AlignViewport;
10 import jalview.gui.FeatureRenderer;
11 import jalview.io.DataSourceType;
12 import jalview.io.FileLoader;
13 import jalview.schemes.FeatureColour;
14
15 import java.awt.Color;
16
17 import org.testng.annotations.BeforeClass;
18 import org.testng.annotations.BeforeMethod;
19 import org.testng.annotations.Test;
20
21 /**
22  * Unit tests for feature colour determination, including but not limited to
23  * <ul>
24  * <li>gap position</li>
25  * <li>no features present</li>
26  * <li>features present but show features turned off</li>
27  * <li>features displayed but selected feature turned off</li>
28  * <li>features displayed but feature group turned off</li>
29  * <li>feature displayed but none at the specified position</li>
30  * <li>multiple features at position, with no transparency</li>
31  * <li>multiple features at position, with transparency</li>
32  * <li>score graduated feature colour</li>
33  * <li>contact feature start at the selected position</li>
34  * <li>contact feature end at the selected position</li>
35  * <li>contact feature straddling the selected position (not shown)</li>
36  * </ul>
37  */
38 public class FeatureColourFinderTest
39 {
40   private AlignViewport av;
41
42   private SequenceI seq;
43
44   private FeatureColourFinder finder;
45
46   private AlignFrame af;
47
48   private FeatureRenderer fr;
49
50   @BeforeClass(alwaysRun = true)
51   public void setUp()
52   {
53     // aligned column 8 is sequence position 6
54     String s = ">s1\nABCDE---FGHIJKLMNOPQRSTUVWXYZ\n";
55     af = new FileLoader().LoadFileWaitTillLoaded(s,
56             DataSourceType.PASTE);
57     av = af.getViewport();
58     seq = av.getAlignment().getSequenceAt(0);
59     fr = af.getFeatureRenderer();
60     finder = new FeatureColourFinder(fr);
61   }
62
63   /**
64    * Clear down any sequence features before each test
65    */
66   @BeforeMethod(alwaysRun = true)
67   public void setUpBeforeTest()
68   {
69     SequenceFeature[] sfs = seq.getSequenceFeatures();
70     if (sfs != null)
71     {
72       for (SequenceFeature sf : sfs)
73       {
74         seq.deleteFeature(sf);
75       }
76     }
77     fr.findAllFeatures(true);
78
79     /*
80      * reset all feature groups to visible
81      */
82     for (String group : fr.getGroups(false))
83     {
84       fr.setGroupVisibility(group, true);
85     }
86   }
87
88   @Test(groups = "Functional")
89   public void testFindFeatureColour_noFeatures()
90   {
91     av.setShowSequenceFeatures(false);
92     Color c = finder.findFeatureColour(Color.blue, seq, 10);
93     assertEquals(c, Color.blue);
94
95     av.setShowSequenceFeatures(true);
96     c = finder.findFeatureColour(Color.blue, seq, 10);
97     assertEquals(c, Color.blue);
98   }
99
100   @Test(groups = "Functional")
101   public void testFindFeatureColour_noFeaturesShown()
102   {
103     seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
104             Float.NaN, "MetalGroup"));
105     fr.featuresAdded();
106     av.setShowSequenceFeatures(false);
107     Color c = finder.findFeatureColour(Color.blue, seq, 10);
108     assertEquals(c, Color.blue);
109   }
110
111   @Test(groups = "Functional")
112   public void testFindFeatureColour_singleFeatureAtPosition()
113   {
114     seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
115             Float.NaN, "MetalGroup"));
116     fr.setColour("Metal", new FeatureColour(Color.red));
117     fr.featuresAdded();
118     av.setShowSequenceFeatures(true);
119     Color c = finder.findFeatureColour(Color.blue, seq, 10);
120     assertEquals(c, Color.red);
121   }
122
123   @Test(groups = "Functional")
124   public void testFindFeatureColour_gapPosition()
125   {
126     seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12, 0f,
127             null));
128     fr.setColour("Metal", new FeatureColour(Color.red));
129     fr.featuresAdded();
130     av.setShowSequenceFeatures(true);
131     Color c = finder.findFeatureColour(null, seq, 6);
132     assertEquals(c, Color.white);
133   }
134
135   @Test(groups = "Functional")
136   public void testFindFeatureColour_multipleFeaturesAtPositionNoTransparency()
137   {
138     /*
139      * featuresAdded -> FeatureRendererModel.updateRenderOrder which adds any
140      * new features 'on top' (but reverses the order of any added features)
141      */
142     seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
143             Float.NaN, "MetalGroup"));
144     FeatureColour red = new FeatureColour(Color.red);
145     fr.setColour("Metal", red);
146     fr.featuresAdded();
147     seq.addSequenceFeature(new SequenceFeature("Domain", "Domain", 4, 15,
148             Float.NaN, "DomainGroup"));
149     FeatureColour green = new FeatureColour(Color.green);
150     fr.setColour("Domain", green);
151     fr.featuresAdded();
152     av.setShowSequenceFeatures(true);
153
154     /*
155      * expect Domain (green) to be rendered above Metal (red)
156      */
157     Color c = finder.findFeatureColour(Color.blue, seq, 10);
158     assertEquals(c, Color.green);
159
160     /*
161      * now promote Metal above Domain
162      * - currently no way other than mimicking reordering of
163      * table in Feature Settings
164      */
165     Object[][] data = new Object[2][];
166     data[0] = new Object[] { "Metal", red, true };
167     data[1] = new Object[] { "Domain", green, true };
168     fr.setFeaturePriority(data);
169     c = finder.findFeatureColour(Color.blue, seq, 10);
170     assertEquals(c, Color.red);
171
172     /*
173      * ..and turn off display of Metal
174      */
175     data[0][2] = false;
176     fr.setFeaturePriority(data);
177     c = finder.findFeatureColour(Color.blue, seq, 10);
178     assertEquals(c, Color.green);
179   }
180
181   @Test(groups = "Functional")
182   public void testFindFeatureColour_singleFeatureNotAtPosition()
183   {
184     seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 8, 12,
185             Float.NaN, "MetalGroup"));
186     fr.setColour("Metal", new FeatureColour(Color.red));
187     fr.featuresAdded();
188     av.setShowSequenceFeatures(true);
189     // column 2 = sequence position 3
190     Color c = finder.findFeatureColour(Color.blue, seq, 2);
191     assertEquals(c, Color.blue);
192   }
193
194   @Test(groups = "Functional")
195   public void testFindFeatureColour_featureTypeNotDisplayed()
196   {
197     seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
198             Float.NaN, "MetalGroup"));
199     FeatureColour red = new FeatureColour(Color.red);
200     fr.setColour("Metal", red);
201     fr.featuresAdded();
202     av.setShowSequenceFeatures(true);
203     Color c = finder.findFeatureColour(Color.blue, seq, 10);
204     assertEquals(c, Color.red);
205
206     /*
207      * turn off display of Metal - is this the easiest way to do it??
208      */
209     Object[][] data = new Object[1][];
210     data[0] = new Object[] { "Metal", red, false };
211     fr.setFeaturePriority(data);
212     c = finder.findFeatureColour(Color.blue, seq, 10);
213     assertEquals(c, Color.blue);
214
215     /*
216      * turn display of Metal back on
217      */
218     data[0] = new Object[] { "Metal", red, true };
219     fr.setFeaturePriority(data);
220     c = finder.findFeatureColour(Color.blue, seq, 10);
221     assertEquals(c, Color.red);
222   }
223
224   @Test(groups = "Functional")
225   public void testFindFeatureColour_featureGroupNotDisplayed()
226   {
227     seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
228             Float.NaN, "MetalGroup"));
229     FeatureColour red = new FeatureColour(Color.red);
230     fr.setColour("Metal", red);
231     fr.featuresAdded();
232     av.setShowSequenceFeatures(true);
233     Color c = finder.findFeatureColour(Color.blue, seq, 10);
234     assertEquals(c, Color.red);
235
236     /*
237      * turn off display of MetalGroup
238      */
239     fr.setGroupVisibility("MetalGroup", false);
240     c = finder.findFeatureColour(Color.blue, seq, 10);
241     assertEquals(c, Color.blue);
242
243     /*
244      * turn display of MetalGroup back on
245      */
246     fr.setGroupVisibility("MetalGroup", true);
247     c = finder.findFeatureColour(Color.blue, seq, 10);
248     assertEquals(c, Color.red);
249   }
250
251   @Test(groups = "Functional")
252   public void testFindFeatureColour_contactFeature()
253   {
254     /*
255      * currently contact feature == type "Disulphide Bond" or "Disulfide Bond" !!
256      */
257     seq.addSequenceFeature(new SequenceFeature("Disulphide Bond",
258             "Contact", 2, 12, Float.NaN, "Disulphide"));
259     fr.setColour("Disulphide Bond", new FeatureColour(Color.red));
260     fr.featuresAdded();
261     av.setShowSequenceFeatures(true);
262
263     /*
264      * Contact positions are residues 2 and 12
265      * which are columns 1 and 14
266      * positions in between don't count for a contact feature!
267      */
268     Color c = finder.findFeatureColour(Color.blue, seq, 10);
269     assertEquals(c, Color.blue);
270     c = finder.findFeatureColour(Color.blue, seq, 8);
271     assertEquals(c, Color.blue);
272     c = finder.findFeatureColour(Color.blue, seq, 1);
273     assertEquals(c, Color.red);
274     c = finder.findFeatureColour(Color.blue, seq, 14);
275     assertEquals(c, Color.red);
276   }
277
278   @Test(groups = "Functional")
279   public void testFindFeatureColour_graduatedFeatureColour()
280   {
281     seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 2,
282             2, 0f, "KdGroup"));
283     seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 4,
284             4, 5f, "KdGroup"));
285     seq.addSequenceFeature(new SequenceFeature("kd", "hydrophobicity", 7,
286             7, 10f, "KdGroup"));
287
288     /*
289      * graduated colour from 0 to 10
290      */
291     Color min = new Color(100, 50, 150);
292     Color max = new Color(200, 0, 100);
293     FeatureColourI fc = new FeatureColour(min, max, 0, 10);
294     fr.setColour("kd", fc);
295     fr.featuresAdded();
296     av.setShowSequenceFeatures(true);
297
298     /*
299      * position 2, column 1, score 0 - minimum colour in range
300      */
301     Color c = finder.findFeatureColour(Color.blue, seq, 1);
302     assertEquals(c, min);
303
304     /*
305      * position 7, column 9, score 10 - maximum colour in range
306      */
307     c = finder.findFeatureColour(Color.blue, seq, 9);
308     assertEquals(c, max);
309
310     /*
311      * position 4, column 3, score 5 - half way from min to max
312      */
313     c = finder.findFeatureColour(Color.blue, seq, 3);
314     assertEquals(c, new Color(150, 25, 125));
315   }
316
317   @Test(groups = "Functional")
318   public void testFindFeatureColour_transparencySingleFeature()
319   {
320     seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
321             Float.NaN, "MetalGroup"));
322     FeatureColour red = new FeatureColour(Color.red);
323     fr.setColour("Metal", red);
324     fr.featuresAdded();
325     av.setShowSequenceFeatures(true);
326   
327     /*
328      * the FeatureSettings transparency slider has range 0-70 which
329      * corresponds to a transparency value of 1 - 0.3
330      * A value of 0.4 gives a combination of
331      * 0.4 * red(255, 0, 0) + 0.6 * cyan(0, 255, 255) = (102, 153, 153)
332      */
333     fr.setTransparency(0.4f);
334     Color c = finder.findFeatureColour(Color.cyan, seq, 10);
335     assertEquals(c, new Color(102, 153, 153));
336   }
337
338   @Test(groups = "Functional")
339   public void testFindFeatureColour_transparencyTwoFeatures()
340   {
341     seq.addSequenceFeature(new SequenceFeature("Metal", "Metal", 2, 12,
342             Float.NaN, "MetalGroup"));
343     FeatureColour red = new FeatureColour(Color.red);
344     fr.setColour("Metal", red);
345     fr.featuresAdded();
346     seq.addSequenceFeature(new SequenceFeature("Domain", "Domain", 4, 15,
347             Float.NaN, "DomainGroup"));
348     FeatureColour green = new FeatureColour(Color.green);
349     fr.setColour("Domain", green);
350     fr.featuresAdded();
351     av.setShowSequenceFeatures(true);
352   
353     /*
354      * Domain (green) rendered above Metal (red) above background (cyan)
355      * 1) 0.6 * red(255, 0, 0) + 0.4 * cyan(0, 255, 255) = (153, 102, 102)
356      * 2) 0.6* green(0, 255, 0) + 0.4 * (153, 102, 102) = (61, 194, 41) rounded
357      */
358     fr.setTransparency(0.6f);
359     Color c = finder.findFeatureColour(Color.cyan, seq, 10);
360     assertEquals(c, new Color(61, 194, 41));
361   
362     /*
363      * now promote Metal above Domain
364      * - currently no way other than mimicking reordering of
365      * table in Feature Settings
366      * Metal (red) rendered above Domain (green) above background (cyan)
367      * 1) 0.6 * green(0, 255, 0) + 0.4 * cyan(0, 255, 255) = (0, 255, 102)
368      * 2) 0.6* red(255, 0, 0) + 0.4 * (0, 255, 102) = (153, 102, 41) rounded
369      */
370     Object[][] data = new Object[2][];
371     data[0] = new Object[] { "Metal", red, true };
372     data[1] = new Object[] { "Domain", green, true };
373     fr.setFeaturePriority(data);
374     c = finder.findFeatureColour(Color.cyan, seq, 10);
375     assertEquals(c, new Color(153, 102, 41));
376   
377     /*
378      * ..and turn off display of Metal
379      * Domain (green) above background (pink)
380      * 0.6 * green(0, 255, 0) + 0.4 * pink(255, 175, 175) = (102, 223, 70)
381      */
382     data[0][2] = false;
383     fr.setFeaturePriority(data);
384     c = finder.findFeatureColour(Color.pink, seq, 10);
385     assertEquals(c, new Color(102, 223, 70));
386   }
387 }